forked from sailfishos/ofono
Compare commits
3 Commits
mer/1.24+g
...
mer/1.24+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09e6f35a23 | ||
|
|
6dddf527d5 | ||
|
|
a9de07c2bb |
@@ -126,58 +126,7 @@ builtin_modules += sailfish_access
|
||||
builtin_sources += plugins/sailfish_access.c
|
||||
endif
|
||||
|
||||
if DATAFILES
|
||||
dist_conf_DATA += drivers/ril/ril_subscription.conf
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_forward.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_connman.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_devmon.c \
|
||||
drivers/ril/ril_devmon_auto.c \
|
||||
drivers/ril/ril_devmon_combine.c \
|
||||
drivers/ril/ril_devmon_ds.c \
|
||||
drivers/ril/ril_devmon_ss.c \
|
||||
drivers/ril/ril_devmon_ur.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_netmon.c \
|
||||
drivers/ril/ril_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
drivers/ril/ril_phonebook.c \
|
||||
drivers/ril/ril_plugin.c \
|
||||
drivers/ril/ril_radio.c \
|
||||
drivers/ril/ril_radio_caps.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_settings.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
drivers/ril/ril_ussd.c \
|
||||
drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_vendor.c \
|
||||
drivers/ril/ril_voicecall.c
|
||||
|
||||
# Vendor specific extensions
|
||||
builtin_sources += drivers/ril/ril_vendor_mtk.c
|
||||
|
||||
else
|
||||
|
||||
builtin_sources += $(gril_sources)
|
||||
|
||||
builtin_modules += rildev
|
||||
@@ -218,7 +167,6 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
|
||||
drivers/infineonmodem/infineon_constants.h \
|
||||
drivers/rilmodem/lte.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if ISIMODEM
|
||||
builtin_modules += isimodem
|
||||
@@ -488,7 +436,7 @@ builtin_sources += drivers/cdmamodem/cdmamodem.h \
|
||||
drivers/cdmamodem/connman.c
|
||||
endif
|
||||
|
||||
if !RILMODEM
|
||||
if EXTRA_MODEMS
|
||||
builtin_modules += g1
|
||||
builtin_sources += plugins/g1.c
|
||||
|
||||
@@ -567,9 +515,6 @@ builtin_sources += plugins/sim900.c
|
||||
builtin_modules += sim7100
|
||||
builtin_sources += plugins/sim7100.c
|
||||
|
||||
builtin_modules += connman
|
||||
builtin_sources += plugins/connman.c
|
||||
|
||||
builtin_modules += telit
|
||||
builtin_sources += plugins/telit.c
|
||||
|
||||
@@ -1036,45 +981,6 @@ unit_objects += $(unit_test_dbus_access_OBJECTS)
|
||||
unit_tests += unit/test-dbus-access
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
unit_test_conf_SOURCES = unit/test-conf.c drivers/ril/ril_util.c \
|
||||
src/conf.c src/util.c src/log.c
|
||||
unit_test_conf_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_conf_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_conf_OBJECTS)
|
||||
unit_tests += unit/test-conf
|
||||
|
||||
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
|
||||
drivers/ril/ril_config.c src/conf.c src/util.c src/log.c
|
||||
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||
unit_tests += unit/test-ril_config
|
||||
|
||||
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
|
||||
drivers/ril/ril_ecclist.c src/log.c
|
||||
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
|
||||
unit_tests += unit/test-ril_ecclist
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/util.c src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
unit_test_ril_vendor_SOURCES = unit/test-ril_vendor.c unit/fake_watch.c \
|
||||
drivers/ril/ril_vendor.c drivers/ril/ril_vendor_mtk.c \
|
||||
drivers/ril/ril_util.c src/util.c src/log.c
|
||||
unit_test_ril_vendor_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_vendor_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_vendor_OBJECTS)
|
||||
unit_tests += unit/test-ril_vendor
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
@@ -1082,7 +988,6 @@ unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-gprs
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
if ELL
|
||||
if MBIMMODEM
|
||||
|
||||
@@ -177,33 +177,17 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
||||
[enable_rilmodem=${enableval}])
|
||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
[enable Sailfish RIL modem]),
|
||||
[enable_sailfish_rilmodem=${enableval}],
|
||||
[enable_sailfish_rilmodem="no"])
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
AC_ARG_ENABLE(extra-modems,
|
||||
AC_HELP_STRING([--enable-extra-modems],
|
||||
[enable modems not used by Sailfish OS]),
|
||||
[enable_extra_modems=${enableval}])
|
||||
AM_CONDITIONAL(EXTRA_MODEMS, test "${enable_extra_modems}" = "yes")
|
||||
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.49, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.49 is required))
|
||||
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
|
||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.38, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.38 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.6 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(sailfish-manager,
|
||||
AC_HELP_STRING([--enable-sailfish-manager],
|
||||
[enable Sailfish OS modem manager plugin]),
|
||||
[enable_sailfish_manager=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
||||
|
||||
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
|
||||
AC_MSG_ERROR(dbus-glib is required by unit tests))
|
||||
AC_SUBST(DBUS_GLIB_CFLAGS)
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
/* See 3GPP 27.007 7.4 for possible values */
|
||||
#define RIL_MAX_SERVICE_LENGTH 3
|
||||
|
||||
/*
|
||||
* ril.h does not state that string count must be given, but that is
|
||||
* still expected by the modem
|
||||
*/
|
||||
#define RIL_SET_STRING_COUNT 5
|
||||
#define RIL_SET_PW_STRING_COUNT 3
|
||||
|
||||
struct ril_call_barring {
|
||||
struct ril_sim_card *card;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_barring_cbd {
|
||||
struct ril_call_barring *bd;
|
||||
union _ofono_call_barring_cb {
|
||||
ofono_call_barring_query_cb_t query;
|
||||
ofono_call_barring_set_cb_t set;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_barring_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_barring *ril_call_barring_get_data(
|
||||
struct ofono_call_barring *b)
|
||||
{
|
||||
return ofono_call_barring_get_data(b);
|
||||
}
|
||||
|
||||
static struct ril_call_barring_cbd *ril_call_barring_cbd_new(
|
||||
struct ril_call_barring *bd, void *cb, void *data)
|
||||
{
|
||||
struct ril_call_barring_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_barring_cbd, 1);
|
||||
cbd->bd = bd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_barring_submit_request(struct ril_call_barring *bd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(bd->q, req, code, response,
|
||||
ril_call_barring_cbd_free,
|
||||
ril_call_barring_cbd_new(bd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_call_barring_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_query_cb_t cb = cbd->cb.query;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int bearer_class = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
/*
|
||||
* Services for which the specified barring facility is active.
|
||||
* "0" means "disabled for all, -1 if unknown"
|
||||
*/
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* count */
|
||||
grilio_parser_get_int32(&rilp, &bearer_class);
|
||||
DBG("Active services: %d", bearer_class);
|
||||
cb(ril_error_ok(&error), bearer_class, cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring query error %d", status);
|
||||
cb(ril_error_failure(&error), 0, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_query(struct ofono_call_barring *b,
|
||||
const char *lock, int cls,
|
||||
ofono_call_barring_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req;
|
||||
|
||||
DBG("lock: %s, services to query: %d", lock, cls);
|
||||
|
||||
/*
|
||||
* RIL modems do not support 7 as default bearer class. According to
|
||||
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||
* "All tele and bearer services"
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/*
|
||||
* See 3GPP 27.007 7.4 for parameter descriptions.
|
||||
*/
|
||||
req = grilio_request_array_utf8_new(4, lock, "", cls_textual,
|
||||
ril_sim_card_app_aid(bd->card));
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK,
|
||||
ril_call_barring_query_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring Set error %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_set(struct ofono_call_barring *b,
|
||||
const char *lock, int enable, const char *passwd, int cls,
|
||||
ofono_call_barring_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
char cls_textual[RIL_MAX_SERVICE_LENGTH];
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
|
||||
|
||||
/*
|
||||
* RIL modem does not support 7 as default bearer class. According to
|
||||
* the 22.030 Annex C: When service code is not given it corresponds to
|
||||
* "All tele and bearer services"
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
sprintf(cls_textual, "%d", cls);
|
||||
|
||||
/* See 3GPP 27.007 7.4 for parameter descriptions */
|
||||
grilio_request_append_int32(req, RIL_SET_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_utf8(req, enable ?
|
||||
RIL_FACILITY_LOCK :
|
||||
RIL_FACILITY_UNLOCK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, cls_textual);
|
||||
grilio_request_append_utf8(req, ril_sim_card_app_aid(bd->card));
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
ril_call_barring_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_barring_cbd *cbd = user_data;
|
||||
ofono_call_barring_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Call Barring Set PW error %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_barring_set_passwd(struct ofono_call_barring *b,
|
||||
const char *lock, const char *old_passwd,
|
||||
const char *new_passwd, ofono_call_barring_set_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG("");
|
||||
grilio_request_append_int32(req, RIL_SET_PW_STRING_COUNT);
|
||||
grilio_request_append_utf8(req, lock); /* Facility code */
|
||||
grilio_request_append_utf8(req, old_passwd);
|
||||
grilio_request_append_utf8(req, new_passwd);
|
||||
|
||||
ril_call_barring_submit_request(bd, req,
|
||||
RIL_REQUEST_CHANGE_BARRING_PASSWORD,
|
||||
ril_call_barring_set_passwd_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_barring_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_barring *b = user_data;
|
||||
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||
|
||||
GASSERT(bd->timer_id);
|
||||
bd->timer_id = 0;
|
||||
ofono_call_barring_register(b);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_barring_probe(struct ofono_call_barring *b,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
|
||||
|
||||
DBG("");
|
||||
bd->card = ril_sim_card_ref(modem->sim_card);
|
||||
bd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
bd->timer_id = g_idle_add(ril_call_barring_register, b);
|
||||
ofono_call_barring_set_data(b, bd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_barring_remove(struct ofono_call_barring *b)
|
||||
{
|
||||
struct ril_call_barring *bd = ril_call_barring_get_data(b);
|
||||
|
||||
DBG("");
|
||||
ofono_call_barring_set_data(b, NULL);
|
||||
|
||||
if (bd->timer_id > 0) {
|
||||
g_source_remove(bd->timer_id);
|
||||
}
|
||||
|
||||
ril_sim_card_unref(bd->card);
|
||||
grilio_queue_cancel_all(bd->q, FALSE);
|
||||
grilio_queue_unref(bd->q);
|
||||
g_free(bd);
|
||||
}
|
||||
|
||||
const struct ofono_call_barring_driver ril_call_barring_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_barring_probe,
|
||||
.remove = ril_call_barring_remove,
|
||||
.query = ril_call_barring_query,
|
||||
.set = ril_call_barring_set,
|
||||
.set_passwd = ril_call_barring_set_passwd
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
struct ril_call_forward {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
enum ril_call_forward_action {
|
||||
CF_ACTION_DISABLE,
|
||||
CF_ACTION_ENABLE,
|
||||
CF_ACTION_INTERROGATE,
|
||||
CF_ACTION_REGISTRATION,
|
||||
CF_ACTION_ERASURE
|
||||
};
|
||||
|
||||
#define CF_TIME_DEFAULT (0)
|
||||
|
||||
struct ril_call_forward_cbd {
|
||||
struct ril_call_forward *fd;
|
||||
union _ofono_call_forward_cb {
|
||||
ofono_call_forwarding_query_cb_t query;
|
||||
ofono_call_forwarding_set_cb_t set;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_call_forward *ril_call_forward_get_data(
|
||||
struct ofono_call_forwarding *cf)
|
||||
{
|
||||
return ofono_call_forwarding_get_data(cf);
|
||||
}
|
||||
|
||||
static void ril_call_forward_cbd_free(gpointer cbd)
|
||||
{
|
||||
g_slice_free(struct ril_call_forward_cbd, cbd);
|
||||
}
|
||||
|
||||
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_forward_cbd *cbd;
|
||||
|
||||
cbd = g_slice_new0(struct ril_call_forward_cbd);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
|
||||
int type, int cls, const struct ofono_phone_number *number, int time)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
/*
|
||||
* Modem seems to respond with error to all requests
|
||||
* made with bearer class BEARER_CLASS_DEFAULT.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = SERVICE_CLASS_NONE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, action);
|
||||
grilio_request_append_int32(req, type);
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
if (number) {
|
||||
grilio_request_append_int32(req, number->type);
|
||||
grilio_request_append_utf8(req, number->number);
|
||||
} else {
|
||||
grilio_request_append_int32(req, 0x81); /* TOA unknown */
|
||||
grilio_request_append_utf8(req, NULL); /* No number */
|
||||
}
|
||||
grilio_request_append_int32(req, time);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_forward_cbd *cbd = user_data;
|
||||
ofono_call_forwarding_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("CF setting failed");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_set(struct ofono_call_forwarding *cf,
|
||||
enum ril_call_forward_action cmd, int type, int cls,
|
||||
const struct ofono_phone_number *number, int time,
|
||||
ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
|
||||
|
||||
grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
|
||||
ril_call_forward_set_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, const struct ofono_phone_number *number,
|
||||
int time, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf registration");
|
||||
ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
|
||||
number, time, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf erasure");
|
||||
ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf disable");
|
||||
ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_activate(struct ofono_call_forwarding *cf,
|
||||
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
|
||||
{
|
||||
ofono_info("cf enable");
|
||||
ril_call_forward_set(cf, CF_ACTION_ENABLE, type, cls,
|
||||
NULL, CF_TIME_DEFAULT, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_forward_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_forward_cbd *cbd = user_data;
|
||||
ofono_call_forwarding_query_cb_t cb = cbd->cb.query;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
struct ofono_call_forwarding_condition *list = NULL;
|
||||
GRilIoParser rilp;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, &count);
|
||||
|
||||
list = g_new0(struct ofono_call_forwarding_condition, count);
|
||||
for (i = 0; i < count; i++) {
|
||||
struct ofono_call_forwarding_condition *fw = list + i;
|
||||
char *str;
|
||||
|
||||
grilio_parser_get_int32(&rilp, &fw->status);
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
grilio_parser_get_int32(&rilp, &fw->cls);
|
||||
grilio_parser_get_int32(&rilp, &fw->phone_number.type);
|
||||
str = grilio_parser_get_utf8(&rilp);
|
||||
if (str) {
|
||||
strncpy(fw->phone_number.number, str,
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
fw->phone_number.number[
|
||||
OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
|
||||
g_free(str);
|
||||
}
|
||||
grilio_parser_get_int32(&rilp, &fw->time);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), count, list, cbd->data);
|
||||
g_free(list);
|
||||
} else {
|
||||
ofono_error("CF query failed");
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_forward_query(struct ofono_call_forwarding *cf, int type,
|
||||
int cls, ofono_call_forwarding_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
|
||||
type, cls, NULL, CF_TIME_DEFAULT);
|
||||
|
||||
ofono_info("cf query");
|
||||
grilio_queue_send_request_full(fd->q, req,
|
||||
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
|
||||
ril_call_forward_query_cb, ril_call_forward_cbd_free,
|
||||
ril_call_forward_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_forward_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_forwarding *cf = user_data;
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
|
||||
fd->timer_id = 0;
|
||||
ofono_call_forwarding_register(cf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_forward_probe(struct ofono_call_forwarding *cf,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_forward *fd = g_try_new0(struct ril_call_forward, 1);
|
||||
|
||||
DBG("");
|
||||
fd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
fd->timer_id = g_idle_add(ril_call_forward_register, cf);
|
||||
ofono_call_forwarding_set_data(cf, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
|
||||
{
|
||||
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
|
||||
|
||||
DBG("");
|
||||
ofono_call_forwarding_set_data(cf, NULL);
|
||||
|
||||
if (fd->timer_id) {
|
||||
g_source_remove(fd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(fd->q, FALSE);
|
||||
grilio_queue_unref(fd->q);
|
||||
g_free(fd);
|
||||
}
|
||||
|
||||
const struct ofono_call_forwarding_driver ril_call_forwarding_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_forward_probe,
|
||||
.remove = ril_call_forward_remove,
|
||||
.erasure = ril_call_forward_erasure,
|
||||
.deactivation = ril_call_forward_deactivate,
|
||||
.query = ril_call_forward_query,
|
||||
.registration = ril_call_forward_registration,
|
||||
.activation = ril_call_forward_activate
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
struct ril_call_settings {
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_settings_cbd {
|
||||
union _ofono_call_settings_cb {
|
||||
ofono_call_settings_status_cb_t status;
|
||||
ofono_call_settings_set_cb_t set;
|
||||
ofono_call_settings_clir_cb_t clir;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_call_settings_cbd_free g_free
|
||||
|
||||
static inline struct ril_call_settings *ril_call_settings_get_data(
|
||||
struct ofono_call_settings *b)
|
||||
{
|
||||
return ofono_call_settings_get_data(b);
|
||||
}
|
||||
|
||||
static struct ril_call_settings_cbd *ril_call_settings_cbd_new(void *cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_call_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_call_settings_cbd, 1);
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static inline void ril_call_settings_submit_req(struct ril_call_settings *sd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
|
||||
void *cb, void *data)
|
||||
{
|
||||
grilio_queue_send_request_full(sd->q, req, code, response,
|
||||
ril_call_settings_cbd_free,
|
||||
ril_call_settings_cbd_new(cb, data));
|
||||
}
|
||||
|
||||
static void ril_call_settings_clip_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int res = 0;
|
||||
|
||||
/* data length of the response */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &res) && res > 0) {
|
||||
grilio_parser_get_int32(&rilp, &res);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), res, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_set_cb_t cb = cbd->cb.set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_set(struct ofono_call_settings *cs, int mode,
|
||||
int cls, ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(12);
|
||||
|
||||
grilio_request_append_int32(req, 2); /* Number of params */
|
||||
grilio_request_append_int32(req, mode); /* on/off */
|
||||
|
||||
/* Modem seems to respond with error to all queries
|
||||
* or settings made with bearer class
|
||||
* BEARER_CLASS_DEFAULT. Design decision: If given
|
||||
* class is BEARER_CLASS_DEFAULT let's map it to
|
||||
* SERVICE_CLASS_VOICE effectively making it the
|
||||
* default bearer. This in line with API which is
|
||||
* contains only voice anyways.
|
||||
*/
|
||||
if (cls == BEARER_CLASS_DEFAULT) {
|
||||
cls = BEARER_CLASS_VOICE;
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, cls); /* Service class */
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CALL_WAITING,
|
||||
ril_call_settings_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_status_cb_t cb = cbd->cb.status;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int res = 0;
|
||||
int sv = 0;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* first value in int[] is len so let's skip that */
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
|
||||
/* status of call waiting service, disabled is returned only if
|
||||
* service is not active for any service class */
|
||||
grilio_parser_get_int32(&rilp, &res);
|
||||
DBG("CW enabled/disabled: %d", res);
|
||||
|
||||
if (res > 0) {
|
||||
/* services for which call waiting is enabled,
|
||||
27.007 7.12 */
|
||||
grilio_parser_get_int32(&rilp, &sv);
|
||||
DBG("CW enabled for: %d", sv);
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), sv, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_cw_query(struct ofono_call_settings *cs, int cls,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
|
||||
/*
|
||||
* RILD expects service class to be 0 as certain carriers can reject
|
||||
* the query with specific service class
|
||||
*/
|
||||
grilio_request_append_int32(req, 0);
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_QUERY_CALL_WAITING,
|
||||
ril_call_settings_cw_query_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clip_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_QUERY_CLIP,
|
||||
ril_call_settings_clip_query_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_settings_cbd *cbd = user_data;
|
||||
ofono_call_settings_clir_cb_t cb = cbd->cb.clir;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int override = -1, network = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
/*first value in int[] is len so let's skip that*/
|
||||
grilio_parser_get_int32(&rilp, NULL);
|
||||
/* Set HideCallerId property from network */
|
||||
grilio_parser_get_int32(&rilp, &override);
|
||||
/* CallingLineRestriction indicates the state of
|
||||
the CLIR supplementary service in the network */
|
||||
grilio_parser_get_int32(&rilp, &network);
|
||||
|
||||
cb(ril_error_ok(&error), override, network, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), -1, -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_query(struct ofono_call_settings *cs,
|
||||
ofono_call_settings_clir_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_GET_CLIR,
|
||||
ril_call_settings_clir_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_call_settings_clir_set(struct ofono_call_settings *cs,
|
||||
int mode, ofono_call_settings_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, mode); /* for outgoing calls */
|
||||
|
||||
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CLIR,
|
||||
ril_call_settings_set_cb, cb, data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_call_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ofono_call_settings *cs = user_data;
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
DBG("");
|
||||
GASSERT(sd->timer_id);
|
||||
sd->timer_id = 0;
|
||||
ofono_call_settings_register(cs);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_settings_probe(struct ofono_call_settings *cs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_settings *sd = g_try_new0(struct ril_call_settings, 1);
|
||||
|
||||
DBG("");
|
||||
sd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
sd->timer_id = g_idle_add(ril_call_settings_register, cs);
|
||||
ofono_call_settings_set_data(cs, sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_settings_remove(struct ofono_call_settings *cs)
|
||||
{
|
||||
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
|
||||
|
||||
DBG("");
|
||||
ofono_call_settings_set_data(cs, NULL);
|
||||
|
||||
if (sd->timer_id > 0) {
|
||||
g_source_remove(sd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_call_settings_driver ril_call_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_settings_probe,
|
||||
.remove = ril_call_settings_remove,
|
||||
.clip_query = ril_call_settings_clip_query,
|
||||
.cw_query = ril_call_settings_cw_query,
|
||||
.cw_set = ril_call_settings_cw_set,
|
||||
.clir_query = ril_call_settings_clir_query,
|
||||
.clir_set = ril_call_settings_clir_set
|
||||
|
||||
/*
|
||||
* Not supported in RIL API
|
||||
* .colp_query = ril_call_settings_colp_query,
|
||||
* .colr_query = ril_call_settings_colr_query
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
struct ril_call_volume {
|
||||
struct ofono_call_volume *v;
|
||||
GRilIoQueue *q;
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_call_volume_req {
|
||||
ofono_call_volume_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_call_volume *ril_call_volume_get_data(
|
||||
struct ofono_call_volume *v)
|
||||
{
|
||||
return ofono_call_volume_get_data(v);
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_call_volume_req *cbd = user_data;
|
||||
ofono_call_volume_cb_t cb = cbd->cb;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Could not set the ril mute state");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_call_volume_mute(struct ofono_call_volume *v, int muted,
|
||||
ofono_call_volume_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||
struct ril_call_volume_req *cbd;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
cbd = g_new(struct ril_call_volume_req, 1);
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
|
||||
DBG("%d", muted);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, muted);
|
||||
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_SET_MUTE,
|
||||
ril_call_volume_mute_cb, g_free, cbd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_call_volume_query_mute_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_call_volume *vd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int muted = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* Array length */
|
||||
grilio_parser_get_int32(&rilp, &muted);
|
||||
DBG("{%d}", muted);
|
||||
ofono_call_volume_set_muted(vd->v, muted);
|
||||
} else {
|
||||
ofono_error("Could not retrive the ril mute state");
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_call_volume_register(gpointer user_data)
|
||||
{
|
||||
struct ril_call_volume *vd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(vd->timer_id);
|
||||
vd->timer_id = 0;
|
||||
ofono_call_volume_register(vd->v);
|
||||
|
||||
/* Probe the mute state */
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_GET_MUTE, ril_call_volume_query_mute_cb, NULL, vd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_call_volume_probe(struct ofono_call_volume *v,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_call_volume *vd = g_new0(struct ril_call_volume, 1);
|
||||
|
||||
DBG("");
|
||||
vd->v = v;
|
||||
vd->q = grilio_queue_new(ril_modem_io(modem));
|
||||
vd->timer_id = g_idle_add(ril_call_volume_register, vd);
|
||||
ofono_call_volume_set_data(v, vd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_call_volume_remove(struct ofono_call_volume *v)
|
||||
{
|
||||
struct ril_call_volume *vd = ril_call_volume_get_data(v);
|
||||
|
||||
DBG("");
|
||||
ofono_call_volume_set_data(v, NULL);
|
||||
|
||||
if (vd->timer_id) {
|
||||
g_source_remove(vd->timer_id);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
const struct ofono_call_volume_driver ril_call_volume_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_call_volume_probe,
|
||||
.remove = ril_call_volume_remove,
|
||||
.mute = ril_call_volume_mute,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct ril_cbs {
|
||||
struct ofono_cbs *cbs;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
guint register_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_cbs_cbd {
|
||||
struct ril_cbs *cd;
|
||||
ofono_cbs_set_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define RIL_CBS_CHECK_RETRY_MS 1000
|
||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
|
||||
|
||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
|
||||
|
||||
#define ril_cbs_cbd_free g_free
|
||||
|
||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
|
||||
|
||||
cbd->cd = cd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_retry(GRilIoRequest *request, int ril_status,
|
||||
const void *resp_data, guint resp_len, void *user_data)
|
||||
{
|
||||
return ril_status == RIL_E_INVALID_STATE;
|
||||
}
|
||||
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
GRilIoRequest* req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
{
|
||||
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
|
||||
int i, n = gutil_strv_length(list);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *entry = list[i];
|
||||
const char *delim = strchr(entry, '-');
|
||||
int from, to;
|
||||
if (delim) {
|
||||
char **range = g_strsplit(topics, "-", 0);
|
||||
from = atoi(range[0]);
|
||||
to = atoi(range[1]);
|
||||
g_strfreev(range);
|
||||
} else {
|
||||
from = to = atoi(entry);
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, from);
|
||||
grilio_request_append_int32(req, to);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, 0xff);
|
||||
grilio_request_append_int32(req, 1);
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
grilio_request_unref(req);
|
||||
g_strfreev(list);
|
||||
}
|
||||
|
||||
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs_cbd *cbd = user_data;
|
||||
|
||||
if (cbd->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "%s", topics);
|
||||
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
|
||||
ofono_cbs_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
|
||||
ril_cbs_cbd_new(cd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
guint32 pdu_len;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &pdu_len)) {
|
||||
const void* pdu = grilio_parser_get_bytes(&rilp, pdu_len);
|
||||
|
||||
/*
|
||||
* By default assume that it's a length followed by the
|
||||
* binary PDU data.
|
||||
*/
|
||||
if (pdu && grilio_parser_bytes_remaining(&rilp) < 4) {
|
||||
DBG_(cd, "%u bytes", pdu_len);
|
||||
ofono_cbs_notify(cd->cbs, pdu, pdu_len);
|
||||
} else {
|
||||
/*
|
||||
* But I've seen cell broadcasts arriving without
|
||||
* the length, simply as a blob.
|
||||
*/
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_register(void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->register_id = 0;
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
cd->cbs = cbs;
|
||||
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
cd->register_id = g_idle_add(ril_cbs_register, cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
{
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
if (cd->register_id) {
|
||||
g_source_remove(cd->register_id);
|
||||
}
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
grilio_queue_cancel_all(cd->q, FALSE);
|
||||
grilio_queue_unref(cd->q);
|
||||
g_free(cd->log_prefix);
|
||||
g_free(cd);
|
||||
}
|
||||
|
||||
const struct ofono_cbs_driver ril_cbs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_cbs_probe,
|
||||
.remove = ril_cbs_remove,
|
||||
.set_topics = ril_cbs_set_topics,
|
||||
.clear_topics = ril_cbs_clear_topics
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,620 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_idlepool.h>
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define DEFAULT_UPDATE_RATE_MS (10000) /* 10 sec */
|
||||
#define MAX_RETRIES (5)
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct ofono_cell_info info;
|
||||
struct ofono_cell **cells;
|
||||
GRilIoChannel *io;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
gulong radio_state_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gboolean sim_card_ready;
|
||||
int update_rate_ms;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
guint set_rate_id;
|
||||
gboolean enabled;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
SIGNAL_CELLS_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_CELLS_CHANGED_NAME "ril-cell-info-cells-changed"
|
||||
|
||||
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
#define PARENT_TYPE G_TYPE_OBJECT
|
||||
#define PARENT_CLASS ril_cell_info_parent_class
|
||||
#define THIS_TYPE (ril_cell_info_get_type())
|
||||
#define THIS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), THIS_TYPE, RilCellInfo))
|
||||
|
||||
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, PARENT_TYPE)
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
|
||||
static const char *ril_cell_info_int_format(int value, const char *format)
|
||||
{
|
||||
if (value == OFONO_CELL_INVALID_VALUE) {
|
||||
return "";
|
||||
} else {
|
||||
static GUtilIdlePool *ril_cell_info_pool = NULL;
|
||||
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
|
||||
char *str = g_strdup_printf(format, value);
|
||||
|
||||
gutil_idle_pool_add(pool, str, g_free);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
static gint ril_cell_info_list_sort_cb(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return ofono_cell_compare_location(*(struct ofono_cell **)a,
|
||||
*(struct ofono_cell **)b);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(const ofono_cell_ptr *l1,
|
||||
const ofono_cell_ptr *l2)
|
||||
{
|
||||
if (l1 && l2) {
|
||||
while (*l1 && *l2) {
|
||||
if (memcmp(*l1, *l2, sizeof(struct ofono_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1++;
|
||||
l2++;
|
||||
}
|
||||
return !*l1 && !*l2;
|
||||
} else {
|
||||
return (!l1 || !*l1) && (!l2 || !*l2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Takes ownership of GPtrArray */
|
||||
static void ril_cell_info_update_cells(RilCellInfo *self, GPtrArray *l)
|
||||
{
|
||||
if (l && !ril_cell_info_list_identical(self->cells,
|
||||
(struct ofono_cell **)l->pdata)) {
|
||||
gutil_ptrv_free((void**)self->cells);
|
||||
self->info.cells = (struct ofono_cell **)
|
||||
g_ptr_array_free(l, FALSE);
|
||||
g_signal_emit(self, ril_cell_info_signals
|
||||
[SIGNAL_CELLS_CHANGED], 0);
|
||||
} else if (l) {
|
||||
g_ptr_array_set_free_func(l, g_free);
|
||||
g_ptr_array_free(l, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ofono_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ofono_cell *cell = g_new0(struct ofono_cell, 1);
|
||||
struct ofono_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = OFONO_CELL_INVALID_VALUE;
|
||||
gsm->bsic = OFONO_CELL_INVALID_VALUE;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = OFONO_CELL_INVALID_VALUE;
|
||||
/* RIL_CellIdentityGsm */
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->lac) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->cid) &&
|
||||
(version < 12 || /* RIL_CellIdentityGsm_v12 part */
|
||||
(grilio_parser_get_int32(rilp, &gsm->arfcn) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bsic))) &&
|
||||
/* RIL_GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
|
||||
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
|
||||
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
|
||||
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
|
||||
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
|
||||
ril_cell_info_int_format(gsm->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
|
||||
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
|
||||
cell->type = OFONO_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ofono_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ofono_cell *cell = g_new0(struct ofono_cell, 1);
|
||||
struct ofono_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = OFONO_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->cid) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->psc) &&
|
||||
(version < 12 || /* RIL_CellIdentityWcdma_v12 part */
|
||||
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
|
||||
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
|
||||
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
|
||||
ril_cell_info_int_format(wcdma->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(wcdma->bitErrorRate,
|
||||
",err=%d"));
|
||||
cell->type = OFONO_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ofono_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ofono_cell *cell = g_new0(struct ofono_cell, 1);
|
||||
struct ofono_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = OFONO_CELL_INVALID_VALUE;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
grilio_parser_get_int32(rilp, <e->pci) &&
|
||||
grilio_parser_get_int32(rilp, <e->tac) &&
|
||||
(version < 12 || /* RIL_CellIdentityLte_v12 part */
|
||||
grilio_parser_get_int32(rilp, <e->earfcn)) &&
|
||||
grilio_parser_get_int32(rilp, <e->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrp) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrq) &&
|
||||
grilio_parser_get_int32(rilp, <e->rssnr) &&
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
|
||||
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
|
||||
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
|
||||
ril_cell_info_int_format(lte->ci, ",ci=%d"),
|
||||
ril_cell_info_int_format(lte->pci, ",pci=%d"),
|
||||
ril_cell_info_int_format(lte->tac, ",tac=%d"),
|
||||
ril_cell_info_int_format(lte->signalStrength,
|
||||
",strength=%d"),
|
||||
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
|
||||
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
|
||||
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
|
||||
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
|
||||
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
|
||||
cell->type = OFONO_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||
struct ofono_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &type) &&
|
||||
grilio_parser_get_int32(rilp, ®) &&
|
||||
/* Skip timestamp */
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct ofono_cell *cell = NULL;
|
||||
|
||||
/* Normalize the boolean value */
|
||||
reg = (reg != FALSE);
|
||||
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
skip = 6;
|
||||
break;
|
||||
default:
|
||||
skip = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GPtrArray *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||
{
|
||||
GPtrArray *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
int i, n;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ofono_cell *c;
|
||||
|
||||
l = g_ptr_array_sized_new(n + 1);
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||
if (c) {
|
||||
g_ptr_array_add(l, c);
|
||||
}
|
||||
}
|
||||
g_ptr_array_sort(l, ril_cell_info_list_sort_cb);
|
||||
g_ptr_array_add(l, NULL);
|
||||
}
|
||||
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return l;
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilCellInfo *self = THIS(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilCellInfo *self = THIS(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self,
|
||||
(status == RIL_E_SUCCESS && self->enabled) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilCellInfo *self = THIS(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(self->set_rate_id);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_retry(GRilIoRequest *request, int ril_status,
|
||||
const void *response_data, guint response_len, void *user_data)
|
||||
{
|
||||
RilCellInfo *self = THIS(user_data);
|
||||
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return self->enabled;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(RilCellInfo *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate(RilCellInfo *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
(self->update_rate_ms >= 0 && self->enabled) ?
|
||||
self->update_rate_ms : INT_MAX);
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(RilCellInfo *self)
|
||||
{
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (self->enabled && self->radio->state == RADIO_STATE_ON &&
|
||||
self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
{
|
||||
RilCellInfo *self = THIS(arg);
|
||||
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
|
||||
ril_cell_info_refresh(self);
|
||||
}
|
||||
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
RilCellInfo *self = THIS(arg);
|
||||
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
/* ofono_cell_info interface callbacks */
|
||||
|
||||
typedef struct ril_cell_info_closure {
|
||||
GCClosure cclosure;
|
||||
ofono_cell_info_cb_t cb;
|
||||
void *arg;
|
||||
} RilCellInfoClosure;
|
||||
|
||||
static inline RilCellInfo *ril_cell_info_cast(struct ofono_cell_info *info)
|
||||
{
|
||||
return G_CAST(info, RilCellInfo, info);
|
||||
}
|
||||
|
||||
static void ril_cell_info_ref_proc(struct ofono_cell_info *info)
|
||||
{
|
||||
g_object_ref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_unref_proc(struct ofono_cell_info *info)
|
||||
{
|
||||
g_object_unref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_changed_cb(RilCellInfo *self,
|
||||
RilCellInfoClosure *closure)
|
||||
{
|
||||
closure->cb(&self->info, closure->arg);
|
||||
}
|
||||
|
||||
static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||
(struct ofono_cell_info *info, ofono_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
if (cb) {
|
||||
RilCellInfoClosure *closure = (RilCellInfoClosure *)
|
||||
g_closure_new_simple(sizeof(RilCellInfoClosure), NULL);
|
||||
GCClosure *cc = &closure->cclosure;
|
||||
|
||||
cc->closure.data = closure;
|
||||
cc->callback = G_CALLBACK(ril_cell_info_cells_changed_cb);
|
||||
closure->cb = cb;
|
||||
closure->arg = arg;
|
||||
return g_signal_connect_closure_by_id(ril_cell_info_cast(info),
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED], 0,
|
||||
&cc->closure, FALSE);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_remove_handler_proc(struct ofono_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_update_interval_proc
|
||||
(struct ofono_cell_info *info, int ms)
|
||||
{
|
||||
RilCellInfo *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->update_rate_ms != ms) {
|
||||
self->update_rate_ms = ms;
|
||||
DBG_(self, "%d ms", ms);
|
||||
if (self->enabled && self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_set_enabled_proc(struct ofono_cell_info *info,
|
||||
gboolean enabled)
|
||||
{
|
||||
RilCellInfo *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->enabled != enabled) {
|
||||
self->enabled = enabled;
|
||||
DBG_(self, "%d", enabled);
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ofono_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card)
|
||||
{
|
||||
RilCellInfo *self = g_object_new(THIS_TYPE, 0);
|
||||
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->radio = ril_radio_ref(radio);
|
||||
self->sim_card = ril_sim_card_ref(sim_card);
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
self->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
self->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
|
||||
/* Disable updates by default */
|
||||
self->enabled = FALSE;
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(RilCellInfo *self)
|
||||
{
|
||||
static const struct ofono_cell_info_proc ril_cell_info_proc = {
|
||||
ril_cell_info_ref_proc,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc,
|
||||
ril_cell_info_set_update_interval_proc,
|
||||
ril_cell_info_set_enabled_proc
|
||||
};
|
||||
|
||||
self->update_rate_ms = DEFAULT_UPDATE_RATE_MS;
|
||||
self->info.cells = self->cells = g_new0(struct ofono_cell*, 1);
|
||||
self->info.proc = &ril_cell_info_proc;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
RilCellInfo *self = THIS(object);
|
||||
|
||||
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||
if (self->query_id) {
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = 0;
|
||||
}
|
||||
if (self->set_rate_id) {
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||
FALSE);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
/* xxx_remove_handlers() zero the ids */
|
||||
ril_radio_remove_handlers(self->radio,
|
||||
&self->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(self->sim_card,
|
||||
&self->sim_status_event_id, 1);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_finalize(GObject *object)
|
||||
{
|
||||
RilCellInfo *self = THIS(object);
|
||||
|
||||
DBG_(self, "");
|
||||
gutil_ptrv_free((void**)self->cells);
|
||||
g_free(self->log_prefix);
|
||||
grilio_channel_unref(self->io);
|
||||
ril_radio_unref(self->radio);
|
||||
ril_sim_card_unref(self->sim_card);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_CELL_INFO_H
|
||||
#define RIL_CELL_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/cell-info.h>
|
||||
|
||||
struct ofono_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_config.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
char *value = ofono_conf_get_string(file, group, key);
|
||||
|
||||
if (value) {
|
||||
GUtilIntArray *array = gutil_int_array_new();
|
||||
char **values, **ptr;
|
||||
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(value, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(value, ",", -1);
|
||||
ptr = values;
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (gutil_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
g_strfreev(values);
|
||||
return gutil_int_array_free_to_ints(array);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
{
|
||||
if (ints) {
|
||||
guint i, n;
|
||||
const int *data = gutil_ints_get_data(ints, &n);
|
||||
GString *buf = g_string_new(NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
if (buf->len > 0) {
|
||||
g_string_append_c(buf, separator);
|
||||
}
|
||||
g_string_append_printf(buf, "%d", data[i]);
|
||||
}
|
||||
return g_string_free(buf, FALSE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_CONFIG_H
|
||||
#define RIL_CONFIG_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/conf.h>
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP OFONO_COMMON_SETTINGS_GROUP
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
#endif /* RIL_CONFIG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,621 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 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_connman.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/gdbus.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define CONNMAN_BUS DBUS_BUS_SYSTEM
|
||||
#define CONNMAN_SERVICE "net.connman"
|
||||
#define CONNMAN_PATH "/"
|
||||
|
||||
#define CONNMAN_GET_PROPERTIES "GetProperties"
|
||||
#define CONNMAN_GET_TECHNOLOGIES "GetTechnologies"
|
||||
#define CONNMAN_PROPERTY_CHANGED "PropertyChanged"
|
||||
#define CONNMAN_TECH_CONNECTED "Connected"
|
||||
#define CONNMAN_TECH_TETHERING "Tethering"
|
||||
|
||||
#define CONNMAN_INTERFACE_(name) "net.connman." name
|
||||
#define CONNMAN_MANAGER_INTERFACE CONNMAN_INTERFACE_("Manager")
|
||||
#define CONNMAN_TECH_INTERFACE CONNMAN_INTERFACE_("Technology")
|
||||
|
||||
#define CONNMAN_TECH_PATH_(name) "/net/connman/technology/" name
|
||||
#define CONNMAN_TECH_PATH_WIFI CONNMAN_TECH_PATH_("wifi")
|
||||
|
||||
#define CONNMAN_TECH_CONNECTED_BIT (0x01)
|
||||
#define CONNMAN_TECH_TETHERING_BIT (0x02)
|
||||
#define CONNMAN_TECH_ALL_PROPERTY_BITS (\
|
||||
CONNMAN_TECH_CONNECTED_BIT | \
|
||||
CONNMAN_TECH_TETHERING_BIT)
|
||||
|
||||
typedef GObjectClass ConnManObjectClass;
|
||||
|
||||
typedef struct connman_tech ConnManTech;
|
||||
|
||||
typedef struct connman_object {
|
||||
GObject object;
|
||||
struct ril_connman pub;
|
||||
guint32 pending_signals;
|
||||
DBusConnection *connection;
|
||||
DBusPendingCall *call;
|
||||
guint service_watch;
|
||||
guint signal_watch;
|
||||
GHashTable *techs;
|
||||
ConnManTech *wifi;
|
||||
} ConnManObject;
|
||||
|
||||
G_DEFINE_TYPE(ConnManObject, connman_object, G_TYPE_OBJECT)
|
||||
#define CONNMAN_OBJECT_TYPE (connman_object_get_type())
|
||||
#define CONNMAN_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
CONNMAN_OBJECT_TYPE, ConnManObject))
|
||||
|
||||
struct connman_tech {
|
||||
ConnManObject *obj;
|
||||
const char *path;
|
||||
gboolean connected;
|
||||
gboolean tethering;
|
||||
};
|
||||
|
||||
typedef struct connman_closure {
|
||||
GCClosure cclosure;
|
||||
ril_connman_property_cb_t callback;
|
||||
gpointer user_data;
|
||||
} ConnManClosure;
|
||||
|
||||
#define connman_closure_new() ((ConnManClosure *) \
|
||||
g_closure_new_simple(sizeof(ConnManClosure), NULL))
|
||||
|
||||
#define SIGNAL_PROPERTY_CHANGED_NAME "ril-connman-property-changed"
|
||||
#define SIGNAL_PROPERTY_DETAIL "%x"
|
||||
#define SIGNAL_PROPERTY_DETAIL_MAX_LEN (8)
|
||||
|
||||
#define SIGNAL_BIT(property) (1 << (property - 1))
|
||||
#define SIGNAL_BIT_(name) SIGNAL_BIT(RIL_CONNMAN_PROPERTY_##name)
|
||||
|
||||
enum connman_object_signal {
|
||||
SIGNAL_PROPERTY_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
static guint connman_object_signals[SIGNAL_COUNT];
|
||||
static GQuark connman_object_property_quarks[RIL_CONNMAN_PROPERTY_COUNT - 1];
|
||||
|
||||
static inline ConnManObject *connman_object_cast(struct ril_connman *connman)
|
||||
{
|
||||
return G_LIKELY(connman) ?
|
||||
CONNMAN_OBJECT(G_CAST(connman, ConnManObject, pub)) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
static inline const char *connman_iter_get_string(DBusMessageIter *it)
|
||||
{
|
||||
const char *str = NULL;
|
||||
|
||||
dbus_message_iter_get_basic(it, &str);
|
||||
return str;
|
||||
}
|
||||
|
||||
static GQuark connman_object_property_quark(enum ril_connman_property p)
|
||||
{
|
||||
/* For ANY property this function is expected to return zero */
|
||||
if (p > RIL_CONNMAN_PROPERTY_ANY && p < RIL_CONNMAN_PROPERTY_COUNT) {
|
||||
const int i = p - 1;
|
||||
|
||||
if (G_UNLIKELY(!connman_object_property_quarks[i])) {
|
||||
char buf[SIGNAL_PROPERTY_DETAIL_MAX_LEN + 1];
|
||||
|
||||
snprintf(buf, sizeof(buf), SIGNAL_PROPERTY_DETAIL, p);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
connman_object_property_quarks[i] =
|
||||
g_quark_from_string(buf);
|
||||
}
|
||||
return connman_object_property_quarks[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connman_object_property_changed(ConnManObject *self,
|
||||
enum ril_connman_property property, ConnManClosure *closure)
|
||||
{
|
||||
closure->callback(&self->pub, property, closure->user_data);
|
||||
}
|
||||
|
||||
static void connman_object_emit_property_change(ConnManObject *self,
|
||||
enum ril_connman_property p)
|
||||
{
|
||||
self->pending_signals &= ~SIGNAL_BIT(p);
|
||||
g_signal_emit(self, connman_object_signals[SIGNAL_PROPERTY_CHANGED],
|
||||
connman_object_property_quark(p), p);
|
||||
}
|
||||
|
||||
static void connman_object_emit_pending_signals(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
gboolean valid_changed, present_changed;
|
||||
enum ril_connman_property p;
|
||||
|
||||
/* Handlers could drop their references to us */
|
||||
g_object_ref(self);
|
||||
|
||||
/*
|
||||
* PRESENT and VALID are the last signals to be emitted if the object
|
||||
* BECOMES present and/or valid.
|
||||
*/
|
||||
if ((self->pending_signals & SIGNAL_BIT_(VALID)) &&
|
||||
connman->valid) {
|
||||
self->pending_signals &= ~SIGNAL_BIT_(VALID);
|
||||
valid_changed = TRUE;
|
||||
} else {
|
||||
valid_changed = FALSE;
|
||||
}
|
||||
if ((self->pending_signals & SIGNAL_BIT_(PRESENT)) &&
|
||||
connman->present) {
|
||||
self->pending_signals &= ~SIGNAL_BIT_(PRESENT);
|
||||
present_changed = TRUE;
|
||||
} else {
|
||||
present_changed = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit the signals. Not that in case if valid has become FALSE,
|
||||
* then VALID is emitted first, otherwise it's emitted last.
|
||||
* Same thing with PRESENT.
|
||||
*/
|
||||
for (p = RIL_CONNMAN_PROPERTY_ANY + 1;
|
||||
p < RIL_CONNMAN_PROPERTY_COUNT && self->pending_signals;
|
||||
p++) {
|
||||
if (self->pending_signals & SIGNAL_BIT(p)) {
|
||||
connman_object_emit_property_change(self, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Then emit PRESENT and VALID if necessary */
|
||||
if (present_changed) {
|
||||
connman_object_emit_property_change(self,
|
||||
RIL_CONNMAN_PROPERTY_PRESENT);
|
||||
}
|
||||
if (valid_changed) {
|
||||
connman_object_emit_property_change(self,
|
||||
RIL_CONNMAN_PROPERTY_VALID);
|
||||
}
|
||||
|
||||
/* And release the temporary reference */
|
||||
g_object_unref(self);
|
||||
}
|
||||
|
||||
static void connman_cancel_call(ConnManObject *self)
|
||||
{
|
||||
if (self->call) {
|
||||
dbus_pending_call_cancel(self->call);
|
||||
dbus_pending_call_unref(self->call);
|
||||
self->call = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static ConnManTech *connman_tech_new(ConnManObject *self, const char *path)
|
||||
{
|
||||
ConnManTech *tech = g_new0(ConnManTech, 1);
|
||||
char *key = g_strdup(path);
|
||||
|
||||
tech->obj = self;
|
||||
tech->path = key;
|
||||
g_hash_table_replace(self->techs, key, tech);
|
||||
return tech;
|
||||
}
|
||||
|
||||
static void connman_invalidate(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (connman->valid) {
|
||||
connman->valid = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_update_valid(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
const gboolean valid = (connman->present && !self->call);
|
||||
|
||||
if (connman->valid != valid) {
|
||||
connman->valid = valid;
|
||||
self->pending_signals |= SIGNAL_BIT_(VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean connman_update_tethering(ConnManObject *self)
|
||||
{
|
||||
struct ril_connman *connman = &self->pub;
|
||||
gboolean tethering = FALSE;
|
||||
GHashTableIter it;
|
||||
gpointer value;
|
||||
|
||||
g_hash_table_iter_init(&it, self->techs);
|
||||
while (g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
const ConnManTech *tech = value;
|
||||
|
||||
if (tech->tethering) {
|
||||
tethering = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (connman->tethering != tethering) {
|
||||
connman->tethering = tethering;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_set_tech_tethering(ConnManTech *tech, gboolean tethering)
|
||||
{
|
||||
if (tech->tethering != tethering) {
|
||||
ConnManObject *self = tech->obj;
|
||||
|
||||
tech->tethering = tethering;
|
||||
DBG(CONNMAN_TECH_TETHERING " %s for %s",
|
||||
tethering ? "on" : "off", tech->path);
|
||||
if (tethering) {
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (G_LIKELY(!connman->tethering)) {
|
||||
/* Definitely tethering now */
|
||||
connman->tethering = TRUE;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
DBG("Tethering on");
|
||||
}
|
||||
} else if (connman_update_tethering(self)) {
|
||||
/* Not tethering anymore */
|
||||
DBG("Tethering off");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_set_tech_connected(ConnManTech *tech, gboolean connected)
|
||||
{
|
||||
if (tech->connected != connected) {
|
||||
ConnManObject *self = tech->obj;
|
||||
|
||||
tech->connected = connected;
|
||||
DBG(CONNMAN_TECH_CONNECTED " %s for %s",
|
||||
connected ? "on" : "off", tech->path);
|
||||
if (tech == self->wifi) {
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
connman->wifi_connected = connected;
|
||||
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
|
||||
DBG("WiFi %sconnected", connected ? "" : "dis");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int connman_tech_set_property(ConnManTech *tech, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter var;
|
||||
DBusBasicValue value;
|
||||
const char *key = connman_iter_get_string(it);
|
||||
|
||||
dbus_message_iter_next(it);
|
||||
dbus_message_iter_recurse(it, &var);
|
||||
dbus_message_iter_get_basic(&var, &value);
|
||||
if (!g_ascii_strcasecmp(key, CONNMAN_TECH_CONNECTED)) {
|
||||
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
|
||||
connman_set_tech_connected(tech, value.bool_val);
|
||||
return CONNMAN_TECH_CONNECTED_BIT;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(key, CONNMAN_TECH_TETHERING)) {
|
||||
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
|
||||
connman_set_tech_tethering(tech, value.bool_val);
|
||||
return CONNMAN_TECH_TETHERING_BIT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connman_tech_set_properties(ConnManTech *tech, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter dict;
|
||||
int handled = 0;
|
||||
|
||||
dbus_message_iter_recurse(it, &dict);
|
||||
while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
|
||||
DBusMessageIter entry;
|
||||
|
||||
dbus_message_iter_recurse(&dict, &entry);
|
||||
handled |= connman_tech_set_property(tech, &entry);
|
||||
if (handled == CONNMAN_TECH_ALL_PROPERTY_BITS) {
|
||||
/* Ignore the rest */
|
||||
break;
|
||||
}
|
||||
dbus_message_iter_next(&dict);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean connman_tech_property_changed(DBusConnection *conn,
|
||||
DBusMessage *msg, void *user_data)
|
||||
{
|
||||
const char *path = dbus_message_get_path(msg);
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
ConnManTech *tech = g_hash_table_lookup(self->techs, path);
|
||||
DBusMessageIter it;
|
||||
|
||||
if (tech && dbus_message_has_signature(msg, "sv") &&
|
||||
dbus_message_iter_init(msg, &it)) {
|
||||
const char* name = connman_iter_get_string(&it);
|
||||
|
||||
if (!connman_tech_set_property(tech, &it)) {
|
||||
DBG("%s changed for %s", name, path);
|
||||
}
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void connman_set_techs(ConnManObject *self, DBusMessageIter *it)
|
||||
{
|
||||
DBusMessageIter list;
|
||||
|
||||
dbus_message_iter_recurse(it, &list);
|
||||
while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
|
||||
DBusMessageIter entry;
|
||||
const char *path;
|
||||
ConnManTech *tech;
|
||||
|
||||
dbus_message_iter_recurse(&list, &entry);
|
||||
path = connman_iter_get_string(&entry);
|
||||
tech = connman_tech_new(self, path);
|
||||
|
||||
DBG("%s", path);
|
||||
if (!g_strcmp0(path, CONNMAN_TECH_PATH_WIFI)) {
|
||||
/* WiFi is a special case */
|
||||
self->wifi = tech;
|
||||
}
|
||||
|
||||
dbus_message_iter_next(&entry);
|
||||
connman_tech_set_properties(tech, &entry);
|
||||
dbus_message_iter_next(&list);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_techs_reply(DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusError error;
|
||||
DBusMessageIter array;
|
||||
|
||||
dbus_error_init(&error);
|
||||
if (dbus_set_error_from_message(&error, reply)) {
|
||||
DBG("Failed to get technologies: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
} else if (dbus_message_has_signature(reply, "a(oa{sv})") &&
|
||||
dbus_message_iter_init(reply, &array)) {
|
||||
connman_set_techs(self, &array);
|
||||
}
|
||||
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(self->call);
|
||||
self->call = NULL;
|
||||
connman_update_valid(self);
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
|
||||
static void connman_get_techs(ConnManObject *self)
|
||||
{
|
||||
DBusMessage *msg = dbus_message_new_method_call(CONNMAN_SERVICE,
|
||||
CONNMAN_PATH, CONNMAN_MANAGER_INTERFACE,
|
||||
CONNMAN_GET_TECHNOLOGIES);
|
||||
|
||||
connman_cancel_call(self);
|
||||
if (g_dbus_send_message_with_reply(self->connection, msg,
|
||||
&self->call, DBUS_TIMEOUT_INFINITE)) {
|
||||
/* Not valid while any request is pending */
|
||||
connman_invalidate(self);
|
||||
dbus_pending_call_set_notify(self->call, connman_techs_reply,
|
||||
self, NULL);
|
||||
}
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void connman_appeared(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (!connman->present) {
|
||||
DBG("connman is there");
|
||||
connman->present = TRUE;
|
||||
self->pending_signals |= SIGNAL_BIT_(PRESENT);
|
||||
connman_get_techs(self);
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_vanished(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(user_data);
|
||||
struct ril_connman *connman = &self->pub;
|
||||
|
||||
if (connman->present) {
|
||||
|
||||
DBG("connman has disappeared");
|
||||
g_hash_table_remove_all(self->techs);
|
||||
self->wifi = NULL;
|
||||
connman->present = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(PRESENT);
|
||||
if (connman->wifi_connected) {
|
||||
connman->wifi_connected = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
|
||||
}
|
||||
if (connman->tethering) {
|
||||
connman->tethering = FALSE;
|
||||
self->pending_signals |= SIGNAL_BIT_(TETHERING);
|
||||
}
|
||||
connman_object_emit_pending_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void connman_init(ConnManObject *self, DBusConnection *connection)
|
||||
{
|
||||
self->connection = dbus_connection_ref(connection);
|
||||
self->service_watch = g_dbus_add_service_watch(self->connection,
|
||||
CONNMAN_SERVICE, connman_appeared, connman_vanished,
|
||||
self, NULL);
|
||||
self->signal_watch = g_dbus_add_signal_watch(self->connection,
|
||||
CONNMAN_SERVICE, NULL, CONNMAN_TECH_INTERFACE,
|
||||
CONNMAN_PROPERTY_CHANGED, connman_tech_property_changed,
|
||||
self, NULL);
|
||||
}
|
||||
|
||||
struct ril_connman *ril_connman_new()
|
||||
{
|
||||
static ConnManObject *instance = NULL;
|
||||
|
||||
if (instance) {
|
||||
g_object_ref(instance);
|
||||
return &instance->pub;
|
||||
} else {
|
||||
DBusError error;
|
||||
DBusConnection *connection;
|
||||
|
||||
dbus_error_init(&error);
|
||||
connection = dbus_bus_get(CONNMAN_BUS, NULL);
|
||||
|
||||
if (connection) {
|
||||
instance = g_object_new(CONNMAN_OBJECT_TYPE, NULL);
|
||||
connman_init(instance, connection);
|
||||
dbus_connection_unref(connection);
|
||||
g_object_add_weak_pointer(G_OBJECT(instance),
|
||||
(gpointer*)(&instance));
|
||||
return &instance->pub;
|
||||
} else {
|
||||
ofono_error("Unable to attach to connman bus: %s",
|
||||
error.message);
|
||||
dbus_error_free(&error);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_connman *ril_connman_ref(struct ril_connman *connman)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(self);
|
||||
return connman;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_connman_unref(struct ril_connman *connman)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(self);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
|
||||
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg)
|
||||
{
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self) && G_LIKELY(cb)) {
|
||||
/*
|
||||
* We can't directly connect the provided callback because
|
||||
* it expects the first parameter to point to public part
|
||||
* of the object but glib will call it with ConnManObject
|
||||
* as the first parameter. connman_object_property_changed()
|
||||
* will do the conversion.
|
||||
*/
|
||||
ConnManClosure *closure = connman_closure_new();
|
||||
GCClosure *cc = &closure->cclosure;
|
||||
|
||||
cc->closure.data = closure;
|
||||
cc->callback = G_CALLBACK(connman_object_property_changed);
|
||||
closure->callback = cb;
|
||||
closure->user_data = arg;
|
||||
|
||||
return g_signal_connect_closure_by_id(self,
|
||||
connman_object_signals[SIGNAL_PROPERTY_CHANGED],
|
||||
connman_object_property_quark(p), &cc->closure, FALSE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ril_connman_remove_handler(struct ril_connman *connman, gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
ConnManObject *self = connman_object_cast(connman);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
|
||||
int n)
|
||||
{
|
||||
gutil_disconnect_handlers(connman_object_cast(connman), ids, n);
|
||||
}
|
||||
|
||||
static void connman_object_init(ConnManObject *self)
|
||||
{
|
||||
self->techs = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
}
|
||||
|
||||
static void connman_object_finalize(GObject *object)
|
||||
{
|
||||
ConnManObject *self = CONNMAN_OBJECT(object);
|
||||
|
||||
connman_cancel_call(self);
|
||||
g_hash_table_destroy(self->techs);
|
||||
g_dbus_remove_watch(self->connection, self->service_watch);
|
||||
g_dbus_remove_watch(self->connection, self->signal_watch);
|
||||
dbus_connection_unref(self->connection);
|
||||
G_OBJECT_CLASS(connman_object_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void connman_object_class_init(ConnManObjectClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = connman_object_finalize;
|
||||
connman_object_signals[SIGNAL_PROPERTY_CHANGED] =
|
||||
g_signal_new(SIGNAL_PROPERTY_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 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_CONNMAN_H
|
||||
#define RIL_CONNMAN_H
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
struct ril_connman {
|
||||
gboolean valid; /* TRUE if other fields are valid */
|
||||
gboolean present; /* ConnMan is present on D-Bus */
|
||||
gboolean tethering; /* At least one technology is tethering */
|
||||
gboolean wifi_connected; /* WiFi network is connected */
|
||||
};
|
||||
|
||||
enum ril_connman_property {
|
||||
RIL_CONNMAN_PROPERTY_ANY,
|
||||
RIL_CONNMAN_PROPERTY_VALID,
|
||||
RIL_CONNMAN_PROPERTY_PRESENT,
|
||||
RIL_CONNMAN_PROPERTY_TETHERING,
|
||||
RIL_CONNMAN_PROPERTY_WIFI_CONNECTED,
|
||||
RIL_CONNMAN_PROPERTY_COUNT
|
||||
};
|
||||
|
||||
typedef void (*ril_connman_property_cb_t)(struct ril_connman *connman,
|
||||
enum ril_connman_property property, void *arg);
|
||||
|
||||
struct ril_connman *ril_connman_new(void);
|
||||
struct ril_connman *ril_connman_ref(struct ril_connman *connman);
|
||||
void ril_connman_unref(struct ril_connman *connman);
|
||||
|
||||
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
|
||||
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg);
|
||||
void ril_connman_remove_handler(struct ril_connman *connman, gulong id);
|
||||
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
|
||||
int n);
|
||||
|
||||
#define ril_connman_remove_all_handlers(connman, ids) \
|
||||
ril_connman_remove_handlers(connman, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_CONNMAN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,399 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __RIL_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#define RIL_MAX_UUID_LENGTH 64
|
||||
|
||||
/* Radio state */
|
||||
enum ril_radio_state {
|
||||
RADIO_STATE_OFF = 0,
|
||||
RADIO_STATE_UNAVAILABLE = 1,
|
||||
RADIO_STATE_SIM_NOT_READY = 2,
|
||||
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
|
||||
RADIO_STATE_SIM_READY = 4,
|
||||
RADIO_STATE_RUIM_NOT_READY = 5,
|
||||
RADIO_STATE_RUIM_READY = 6,
|
||||
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
|
||||
RADIO_STATE_NV_NOT_READY = 8,
|
||||
RADIO_STATE_NV_READY = 9,
|
||||
RADIO_STATE_ON = 10
|
||||
};
|
||||
|
||||
/* Preferred network types */
|
||||
enum ril_pref_net_type {
|
||||
PREF_NET_TYPE_GSM_WCDMA = 0,
|
||||
PREF_NET_TYPE_GSM_ONLY = 1,
|
||||
PREF_NET_TYPE_WCDMA = 2,
|
||||
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
|
||||
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
|
||||
PREF_NET_TYPE_CDMA_ONLY = 5,
|
||||
PREF_NET_TYPE_EVDO_ONLY = 6,
|
||||
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
|
||||
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
|
||||
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
|
||||
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
|
||||
PREF_NET_TYPE_LTE_ONLY = 11,
|
||||
PREF_NET_TYPE_LTE_WCDMA = 12
|
||||
};
|
||||
|
||||
/* Radio technologies */
|
||||
enum ril_radio_tech {
|
||||
RADIO_TECH_UNKNOWN = 0,
|
||||
RADIO_TECH_GPRS = 1,
|
||||
RADIO_TECH_EDGE = 2,
|
||||
RADIO_TECH_UMTS = 3,
|
||||
RADIO_TECH_IS95A = 4,
|
||||
RADIO_TECH_IS95B = 5,
|
||||
RADIO_TECH_1xRTT = 6,
|
||||
RADIO_TECH_EVDO_0 = 7,
|
||||
RADIO_TECH_EVDO_A = 8,
|
||||
RADIO_TECH_HSDPA = 9,
|
||||
RADIO_TECH_HSUPA = 10,
|
||||
RADIO_TECH_HSPA = 11,
|
||||
RADIO_TECH_EVDO_B = 12,
|
||||
RADIO_TECH_EHRPD = 13,
|
||||
RADIO_TECH_LTE = 14,
|
||||
RADIO_TECH_HSPAP = 15,
|
||||
RADIO_TECH_GSM = 16,
|
||||
RADIO_TECH_TD_SCDMA = 17,
|
||||
RADIO_TECH_IWLAN = 18,
|
||||
RADIO_TECH_LTE_CA = 19
|
||||
};
|
||||
|
||||
/* Radio capabilities */
|
||||
enum ril_radio_access_family {
|
||||
RAF_GPRS = (1 << RADIO_TECH_GPRS),
|
||||
RAF_EDGE = (1 << RADIO_TECH_EDGE),
|
||||
RAF_UMTS = (1 << RADIO_TECH_UMTS),
|
||||
RAF_IS95A = (1 << RADIO_TECH_IS95A),
|
||||
RAF_IS95B = (1 << RADIO_TECH_IS95B),
|
||||
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
|
||||
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
|
||||
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
|
||||
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
|
||||
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
|
||||
RAF_HSPA = (1 << RADIO_TECH_HSPA),
|
||||
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
|
||||
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
|
||||
RAF_LTE = (1 << RADIO_TECH_LTE),
|
||||
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
|
||||
RAF_GSM = (1 << RADIO_TECH_GSM),
|
||||
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
|
||||
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
|
||||
};
|
||||
|
||||
enum ril_radio_capability_phase {
|
||||
RC_PHASE_CONFIGURED = 0,
|
||||
RC_PHASE_START = 1,
|
||||
RC_PHASE_APPLY = 2,
|
||||
RC_PHASE_UNSOL_RSP = 3,
|
||||
RC_PHASE_FINISH = 4
|
||||
};
|
||||
|
||||
enum ril_radio_capability_status {
|
||||
RC_STATUS_NONE = 0,
|
||||
RC_STATUS_SUCCESS = 1,
|
||||
RC_STATUS_FAIL = 2
|
||||
};
|
||||
|
||||
#define RIL_RADIO_CAPABILITY_VERSION 1
|
||||
|
||||
struct ril_radio_capability {
|
||||
int version;
|
||||
int session;
|
||||
enum ril_radio_capability_phase phase;
|
||||
enum ril_radio_access_family rat;
|
||||
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
|
||||
int status;
|
||||
};
|
||||
|
||||
enum ril_uicc_subscription_action {
|
||||
RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
|
||||
};
|
||||
|
||||
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
||||
enum ril_call_fail_cause {
|
||||
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
|
||||
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
|
||||
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
|
||||
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
|
||||
CALL_FAIL_NORMAL = 16,
|
||||
CALL_FAIL_BUSY = 17,
|
||||
CALL_FAIL_NO_USER_RESPONDING = 18,
|
||||
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
|
||||
CALL_FAIL_CALL_REJECTED = 21,
|
||||
CALL_FAIL_NUMBER_CHANGED = 22,
|
||||
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
|
||||
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
|
||||
CALL_FAIL_FACILITY_REJECTED = 29,
|
||||
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
|
||||
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
|
||||
CALL_FAIL_CONGESTION = 34,
|
||||
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
|
||||
CALL_FAIL_TEMPORARY_FAILURE = 41,
|
||||
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
|
||||
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
|
||||
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
|
||||
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
|
||||
CALL_FAIL_QOS_UNAVAILABLE = 49,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
|
||||
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
|
||||
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
|
||||
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
|
||||
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
|
||||
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
|
||||
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
|
||||
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
|
||||
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
|
||||
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
|
||||
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
|
||||
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
|
||||
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
|
||||
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
|
||||
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
|
||||
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
|
||||
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
|
||||
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
|
||||
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
|
||||
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
|
||||
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
|
||||
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
|
||||
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
|
||||
CALL_FAIL_CALL_BARRED = 240,
|
||||
CALL_FAIL_FDN_BLOCKED = 241,
|
||||
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
|
||||
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
|
||||
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
|
||||
|
||||
/* Not defined in ril.h but valid 3GPP specific cause values
|
||||
* for call control. See 3GPP TS 24.008 Annex H. */
|
||||
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
|
||||
CALL_FAIL_PRE_EMPTION = 25
|
||||
};
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
PDP_FAIL_OPERATOR_BARRED = 0x08,
|
||||
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
|
||||
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
|
||||
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
|
||||
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
|
||||
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
|
||||
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
|
||||
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
|
||||
PDP_FAIL_NETWORK_FAILURE = 0x26,
|
||||
PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
|
||||
PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
|
||||
PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
|
||||
PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
|
||||
PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
|
||||
PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
|
||||
PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
|
||||
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
|
||||
PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
|
||||
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
|
||||
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
|
||||
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
|
||||
PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
|
||||
PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
|
||||
PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
|
||||
PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
|
||||
PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
|
||||
PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
|
||||
PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
|
||||
PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
|
||||
PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
|
||||
PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
|
||||
PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
|
||||
PDP_FAIL_IFACE_MISMATCH = 0x75,
|
||||
PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
|
||||
PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
|
||||
PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
|
||||
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
|
||||
PDP_FAIL_RADIO_POWER_OFF = -5,
|
||||
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
|
||||
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
|
||||
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
|
||||
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
|
||||
|
||||
/* RIL_REQUEST_SETUP_DATA_CALL */
|
||||
enum ril_data_profile {
|
||||
RIL_DATA_PROFILE_DEFAULT = 0,
|
||||
RIL_DATA_PROFILE_TETHERED = 1,
|
||||
RIL_DATA_PROFILE_IMS = 2,
|
||||
RIL_DATA_PROFILE_FOTA = 3,
|
||||
RIL_DATA_PROFILE_CBS = 4,
|
||||
RIL_DATA_PROFILE_OEM_BASE = 1000,
|
||||
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum ril_profile_type {
|
||||
RIL_PROFILE_COMMON = 0,
|
||||
RIL_PROFILE_3GPP = 1,
|
||||
RIL_PROFILE_3GPP2 = 2
|
||||
};
|
||||
|
||||
enum ril_auth {
|
||||
RIL_AUTH_NONE = 0,
|
||||
RIL_AUTH_PAP = 1,
|
||||
RIL_AUTH_CHAP = 2,
|
||||
RIL_AUTH_BOTH = 3
|
||||
};
|
||||
|
||||
#define RIL_CARD_MAX_APPS 8
|
||||
|
||||
/* SIM card states */
|
||||
enum ril_card_state {
|
||||
RIL_CARDSTATE_UNKNOWN = -1,
|
||||
RIL_CARDSTATE_ABSENT = 0,
|
||||
RIL_CARDSTATE_PRESENT = 1,
|
||||
RIL_CARDSTATE_ERROR = 2
|
||||
};
|
||||
|
||||
/* SIM personalization substates */
|
||||
enum ril_perso_substate {
|
||||
RIL_PERSOSUBSTATE_UNKNOWN = 0,
|
||||
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
|
||||
RIL_PERSOSUBSTATE_READY = 2,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM = 7,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
|
||||
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
|
||||
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
|
||||
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
|
||||
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
|
||||
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
|
||||
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
|
||||
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
|
||||
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
|
||||
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
|
||||
};
|
||||
|
||||
/* SIM - App states */
|
||||
enum ril_app_state {
|
||||
RIL_APPSTATE_ILLEGAL = -1,
|
||||
RIL_APPSTATE_UNKNOWN = 0,
|
||||
RIL_APPSTATE_DETECTED = 1,
|
||||
RIL_APPSTATE_PIN = 2,
|
||||
RIL_APPSTATE_PUK = 3,
|
||||
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
|
||||
RIL_APPSTATE_READY = 5
|
||||
};
|
||||
|
||||
/* SIM - PIN states */
|
||||
enum ril_pin_state {
|
||||
RIL_PINSTATE_UNKNOWN = 0,
|
||||
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
|
||||
RIL_PINSTATE_ENABLED_VERIFIED = 2,
|
||||
RIL_PINSTATE_DISABLED = 3,
|
||||
RIL_PINSTATE_ENABLED_BLOCKED = 4,
|
||||
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
|
||||
};
|
||||
|
||||
/* SIM - App types */
|
||||
enum ril_app_type {
|
||||
RIL_APPTYPE_UNKNOWN = 0,
|
||||
RIL_APPTYPE_SIM = 1,
|
||||
RIL_APPTYPE_USIM = 2,
|
||||
RIL_APPTYPE_RUIM = 3,
|
||||
RIL_APPTYPE_CSIM = 4,
|
||||
RIL_APPTYPE_ISIM = 5
|
||||
};
|
||||
|
||||
/* Cell info */
|
||||
enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_NONE = 0,
|
||||
RIL_CELL_INFO_TYPE_GSM = 1,
|
||||
RIL_CELL_INFO_TYPE_CDMA = 2,
|
||||
RIL_CELL_INFO_TYPE_LTE = 3,
|
||||
RIL_CELL_INFO_TYPE_WCDMA = 4,
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
enum ril_restricted_state {
|
||||
RIL_RESTRICTED_STATE_NONE = 0x00,
|
||||
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
|
||||
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
|
||||
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
|
||||
RIL_RESTRICTED_STATE_PS_ALL = 0x10
|
||||
};
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
/* RIL_FACILITY_LOCK parameters */
|
||||
#define RIL_FACILITY_UNLOCK "0"
|
||||
#define RIL_FACILITY_LOCK "1"
|
||||
|
||||
/* See RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER (RIL_VERSION >= 15) */
|
||||
enum ril_unsolicited_response_filter {
|
||||
RIL_UR_SIGNAL_STRENGTH = 0x01,
|
||||
RIL_UR_FULL_NETWORK_STATE = 0x02,
|
||||
RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE result */
|
||||
enum ril_network_selection_mode {
|
||||
RIL_NETWORK_SELECTION_MODE_AUTO = 0,
|
||||
RIL_NETWORK_SELECTION_MODE_MANUAL = 1
|
||||
};
|
||||
|
||||
#endif /*__RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_DATA_H
|
||||
#define RIL_DATA_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
enum ril_data_call_active {
|
||||
RIL_DATA_CALL_INACTIVE = 0,
|
||||
RIL_DATA_CALL_LINK_DOWN = 1,
|
||||
RIL_DATA_CALL_ACTIVE = 2
|
||||
};
|
||||
|
||||
struct ril_data_call {
|
||||
int cid;
|
||||
enum ril_data_call_fail_cause status;
|
||||
enum ril_data_call_active active;
|
||||
enum ofono_gprs_proto prot;
|
||||
int retry_time;
|
||||
int mtu;
|
||||
char *ifname;
|
||||
char **dnses;
|
||||
char **gateways;
|
||||
char **addresses;
|
||||
char **pcscf;
|
||||
};
|
||||
|
||||
struct ril_data_call_list {
|
||||
guint version;
|
||||
guint num;
|
||||
GSList *calls;
|
||||
};
|
||||
|
||||
struct ril_data {
|
||||
GObject object;
|
||||
struct ril_data_priv *priv;
|
||||
struct ril_data_call_list *data_calls;
|
||||
};
|
||||
|
||||
enum ril_data_manager_flags {
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01,
|
||||
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS = 0x02
|
||||
};
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
RIL_ALLOW_DATA_AUTO,
|
||||
RIL_ALLOW_DATA_ENABLED,
|
||||
RIL_ALLOW_DATA_DISABLED
|
||||
};
|
||||
|
||||
enum ril_data_call_format {
|
||||
RIL_DATA_CALL_FORMAT_AUTO,
|
||||
RIL_DATA_CALL_FORMAT_6 = 6,
|
||||
RIL_DATA_CALL_FORMAT_9 = 9,
|
||||
RIL_DATA_CALL_FORMAT_11 = 11
|
||||
};
|
||||
|
||||
struct ril_data_options {
|
||||
enum ril_data_allow_data_opt allow_data;
|
||||
enum ril_data_call_format data_call_format;
|
||||
unsigned int data_call_retry_limit;
|
||||
unsigned int data_call_retry_delay_ms;
|
||||
};
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
|
||||
int ril_status, const struct ril_data_call *call,
|
||||
void *arg);
|
||||
typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
|
||||
int ril_status, void *arg);
|
||||
|
||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
GRilIoChannel *io, const struct ril_data_options *options,
|
||||
const struct ril_slot_config *config,
|
||||
struct ril_vendor *vendor);
|
||||
struct ril_data *ril_data_ref(struct ril_data *data);
|
||||
void ril_data_unref(struct ril_data *data);
|
||||
gboolean ril_data_allowed(struct ril_data *data);
|
||||
void ril_data_poll_call_state(struct ril_data *data);
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
gulong ril_data_add_calls_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
void ril_data_remove_handler(struct ril_data *data, gulong id);
|
||||
|
||||
void ril_data_allow(struct ril_data *data, enum ril_data_role role);
|
||||
|
||||
struct ril_data_request;
|
||||
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
enum ofono_gprs_context_type context_type,
|
||||
ril_data_call_setup_cb_t cb, void *arg);
|
||||
struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
|
||||
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
|
||||
void ril_data_request_detach(struct ril_data_request *req);
|
||||
void ril_data_request_cancel(struct ril_data_request *req);
|
||||
|
||||
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
|
||||
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
|
||||
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
|
||||
int cid);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
#endif /* RIL_DATA_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_idlequeue.h>
|
||||
|
||||
/*
|
||||
* TODO: No public RIL api to query manufacturer or model.
|
||||
* Check where to get, could /system/build.prop be updated to have good values?
|
||||
*/
|
||||
|
||||
enum ril_devinfo_cb_tag {
|
||||
DEVINFO_QUERY_SERIAL = 1,
|
||||
DEVINFO_QUERY_SVN
|
||||
};
|
||||
|
||||
struct ril_devinfo {
|
||||
struct ofono_devinfo *info;
|
||||
GRilIoQueue *q;
|
||||
GUtilIdleQueue *iq;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
};
|
||||
|
||||
struct ril_devinfo_cbd {
|
||||
struct ril_devinfo *di;
|
||||
ofono_devinfo_query_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
#define ril_devinfo_cbd_free g_free
|
||||
|
||||
static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||
struct ofono_devinfo *info)
|
||||
{
|
||||
return ofono_devinfo_get_data(info);
|
||||
}
|
||||
|
||||
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
|
||||
|
||||
cbd->di = di;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), "", data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
char *res;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
res = grilio_parser_get_utf8(&rilp);
|
||||
DBG_(cbd->di, "%s", res);
|
||||
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
|
||||
g_free(res);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
grilio_queue_send_request_full(di->q, NULL,
|
||||
RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_revision_cb,
|
||||
ril_devinfo_cbd_free,
|
||||
ril_devinfo_cbd_new(di, cb, data));
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(di, "%s", di->imei);
|
||||
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_svn_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(di, "%s", di->imeisv);
|
||||
if (di->imeisv && di->imeisv[0]) {
|
||||
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), "", cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query(struct ril_devinfo *di,
|
||||
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
|
||||
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
|
||||
ril_devinfo_cbd_new(di, cb, data),
|
||||
ril_devinfo_cbd_free);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
|
||||
ril_devinfo_query_serial_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
|
||||
ril_devinfo_query_svn_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_register(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo *di = user_data;
|
||||
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_register(di->info);
|
||||
}
|
||||
|
||||
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
|
||||
|
||||
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
DBG_(di, "%s", modem->imei);
|
||||
GASSERT(modem->imei);
|
||||
|
||||
di->q = grilio_queue_new(ril_modem_io(modem));
|
||||
di->info = info;
|
||||
di->imeisv = g_strdup(modem->imeisv);
|
||||
di->imei = g_strdup(modem->imei);
|
||||
di->iq = gutil_idle_queue_new();
|
||||
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
|
||||
ofono_devinfo_set_data(info, di);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
gutil_idle_queue_cancel_all(di->iq);
|
||||
gutil_idle_queue_unref(di->iq);
|
||||
grilio_queue_cancel_all(di->q, FALSE);
|
||||
grilio_queue_unref(di->q);
|
||||
g_free(di->log_prefix);
|
||||
g_free(di->imeisv);
|
||||
g_free(di->imei);
|
||||
g_free(di);
|
||||
}
|
||||
|
||||
const struct ofono_devinfo_driver ril_devinfo_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_devinfo_probe,
|
||||
.remove = ril_devinfo_remove,
|
||||
/* query_revision won't be called if query_model is missing */
|
||||
.query_model = ril_devinfo_query_unsupported,
|
||||
.query_revision = ril_devinfo_query_revision,
|
||||
.query_serial = ril_devinfo_query_serial,
|
||||
.query_svn = ril_devinfo_query_svn
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 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_devmon.h"
|
||||
|
||||
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *channel, struct ofono_cell_info *cell_info)
|
||||
{
|
||||
return devmon ? devmon->start_io(devmon, channel, cell_info) : NULL;
|
||||
}
|
||||
|
||||
void ril_devmon_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
if (devmon_io) {
|
||||
devmon_io->free(devmon_io);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_devmon_free(struct ril_devmon *devmon)
|
||||
{
|
||||
if (devmon) {
|
||||
devmon->free(devmon);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_DEVMON_H
|
||||
#define RIL_DEVMON_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/cell-info.h>
|
||||
|
||||
/*
|
||||
* Separate instance of ril_devmon is created for each modem.
|
||||
* Device monitor is started after RIL has been connected.
|
||||
*/
|
||||
|
||||
struct ril_devmon_io {
|
||||
void (*free)(struct ril_devmon_io *devmon_io);
|
||||
};
|
||||
|
||||
struct ril_devmon {
|
||||
void (*free)(struct ril_devmon *devmon);
|
||||
struct ril_devmon_io *(*start_io)(struct ril_devmon *devmon,
|
||||
GRilIoChannel *channel, struct ofono_cell_info *cell_info);
|
||||
};
|
||||
|
||||
/*
|
||||
* Legacy Device Monitor uses RIL_REQUEST_SCREEN_STATE to tell
|
||||
* the modem when screen turns on and off.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This Device Monitor uses RIL_REQUEST_SEND_DEVICE_STATE to let
|
||||
* the modem choose the right power saving strategy. It basically
|
||||
* mirrors the logic of Android's DeviceStateMonitor class.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This Device Monitor implementation controls network state updates
|
||||
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This one selects the type based on the RIL version.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This one combines several methods. Takes ownership of ril_devmon objects.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_combine(struct ril_devmon *devmon[], guint n);
|
||||
|
||||
/* Utilities (NULL tolerant) */
|
||||
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *channel, struct ofono_cell_info *cell_info);
|
||||
void ril_devmon_io_free(struct ril_devmon_io *devmon_io);
|
||||
void ril_devmon_free(struct ril_devmon *devmon);
|
||||
|
||||
#endif /* RIL_CONNMAN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
typedef struct ril_devmon_ds {
|
||||
struct ril_devmon pub;
|
||||
struct ril_devmon *ss;
|
||||
struct ril_devmon *ds;
|
||||
} DevMon;
|
||||
|
||||
static inline DevMon *ril_devmon_auto_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_auto_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct ofono_cell_info *cell_info)
|
||||
{
|
||||
DevMon *self = ril_devmon_auto_cast(devmon);
|
||||
|
||||
if (!self->ss) {
|
||||
/* We have already chosen SEND_DEVICE_STATE method */
|
||||
return ril_devmon_start_io(self->ds, io, cell_info);
|
||||
} else if (!self->ds) {
|
||||
/* We have already chosen SCREEN_STATE method */
|
||||
return ril_devmon_start_io(self->ss, io, cell_info);
|
||||
} else if (io->ril_version > 14 /* Covers binder implementation */) {
|
||||
/* Choose SEND_DEVICE_STATE method */
|
||||
DBG("%s: Will use SEND_DEVICE_STATE method", io->name);
|
||||
ril_devmon_free(self->ss);
|
||||
self->ss = NULL;
|
||||
return ril_devmon_start_io(self->ds, io, cell_info);
|
||||
} else {
|
||||
/* Choose legacy SCREEN_STATE method */
|
||||
DBG("%s: Will use SCREEN_STATE method", io->name);
|
||||
ril_devmon_free(self->ds);
|
||||
self->ds = NULL;
|
||||
return ril_devmon_start_io(self->ss, io, cell_info);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_auto_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_auto_cast(devmon);
|
||||
|
||||
ril_devmon_free(self->ss);
|
||||
ril_devmon_free(self->ds);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
/*
|
||||
* Allocate both implementations at startup. We need to do that
|
||||
* early so that connections to D-Bus daemon and services are
|
||||
* established before we drop privileges. This isn't much of
|
||||
* an overhead because those implementation don't do much until
|
||||
* we actually start the I/O (at which point we drop one of those).
|
||||
*/
|
||||
self->pub.free = ril_devmon_auto_free;
|
||||
self->pub.start_io = ril_devmon_auto_start_io;
|
||||
self->ss = ril_devmon_ss_new(config);
|
||||
self->ds = ril_devmon_ds_new(config);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2020-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
typedef struct ril_devmon_combine {
|
||||
struct ril_devmon pub;
|
||||
struct ril_devmon **impl;
|
||||
guint count;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_combine_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ril_devmon_io **impl;
|
||||
guint count;
|
||||
} DevMonIo;
|
||||
|
||||
static inline DevMon *ril_devmon_combine_cast(struct ril_devmon *dm)
|
||||
{
|
||||
return G_CAST(dm, DevMon, pub);
|
||||
}
|
||||
|
||||
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *io)
|
||||
{
|
||||
return G_CAST(io, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static void ril_devmon_combine_io_free(struct ril_devmon_io *io)
|
||||
{
|
||||
guint i;
|
||||
DevMonIo *self = ril_devmon_ds_io_cast(io);
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
ril_devmon_io_free(self->impl[i]);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_combine_start_io(struct ril_devmon *dm,
|
||||
GRilIoChannel *chan, struct ofono_cell_info *ci)
|
||||
{
|
||||
guint i;
|
||||
DevMon *self = ril_devmon_combine_cast(dm);
|
||||
DevMonIo *io = g_malloc0(sizeof(DevMonIo) +
|
||||
sizeof(struct ril_devmon_io *) * self->count);
|
||||
|
||||
io->pub.free = ril_devmon_combine_io_free;
|
||||
io->impl = (struct ril_devmon_io**)(io + 1);
|
||||
io->count = self->count;
|
||||
for (i = 0; i < io->count; i++) {
|
||||
io->impl[i] = ril_devmon_start_io(self->impl[i], chan, ci);
|
||||
}
|
||||
return &io->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_combine_free(struct ril_devmon *dm)
|
||||
{
|
||||
DevMon *self = ril_devmon_combine_cast(dm);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
ril_devmon_free(self->impl[i]);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_combine(struct ril_devmon *dm[], guint n)
|
||||
{
|
||||
guint i;
|
||||
DevMon *self = g_malloc0(sizeof(DevMon) +
|
||||
sizeof(struct ril_devmon *) * n);
|
||||
|
||||
self->pub.free = ril_devmon_combine_free;
|
||||
self->pub.start_io = ril_devmon_combine_start_io;
|
||||
self->impl = (struct ril_devmon **)(self + 1);
|
||||
self->count = n;
|
||||
for (i = 0; i < n; i++) {
|
||||
self->impl[i] = dm[i];
|
||||
}
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,355 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 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_devmon.h"
|
||||
#include "ril_connman.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
enum device_state_type {
|
||||
/* Mirrors RIL_DeviceStateType from ril.h */
|
||||
POWER_SAVE_MODE,
|
||||
CHARGING_STATE,
|
||||
LOW_DATA_EXPECTED
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ds_connman_event {
|
||||
CONNMAN_EVENT_VALID,
|
||||
CONNMAN_EVENT_TETHERING,
|
||||
CONNMAN_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ds {
|
||||
struct ril_devmon pub;
|
||||
struct ril_connman *connman;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ds_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ril_connman *connman;
|
||||
struct ofono_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
guint low_data_req_id;
|
||||
guint charging_req_id;
|
||||
gboolean low_data;
|
||||
gboolean charging;
|
||||
gboolean low_data_supported;
|
||||
gboolean charging_supported;
|
||||
gulong connman_event_id[CONNMAN_EVENT_COUNT];
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMonIo;
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
|
||||
|
||||
static inline DevMon *ril_devmon_ds_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_tethering_on(struct ril_connman *connman)
|
||||
{
|
||||
return connman->valid && connman->tethering;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ds_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static guint ril_devmon_ds_io_send_device_state(DevMonIo *self,
|
||||
enum device_state_type type, gboolean state,
|
||||
GRilIoChannelResponseFunc callback)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(2, type, state);
|
||||
const guint id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SEND_DEVICE_STATE, callback, NULL, self);
|
||||
|
||||
grilio_request_unref(req);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_low_data_state_sent(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->low_data_req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
DBG_(self, "LOW_DATA_EXPECTED state is not supported");
|
||||
self->low_data_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_charging_state_sent(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->charging_req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
DBG_(self, "CHARGING state is not supported");
|
||||
self->charging_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_update_charging(DevMonIo *self)
|
||||
{
|
||||
const gboolean charging = ril_devmon_ds_charging(self->charger);
|
||||
|
||||
if (self->charging != charging) {
|
||||
self->charging = charging;
|
||||
DBG_(self, "Charging %s", charging ? "on" : "off");
|
||||
if (self->charging_supported) {
|
||||
grilio_channel_cancel_request(self->io,
|
||||
self->charging_req_id, FALSE);
|
||||
self->charging_req_id =
|
||||
ril_devmon_ds_io_send_device_state(self,
|
||||
CHARGING_STATE, charging,
|
||||
ril_devmon_ds_io_charging_state_sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_update_low_data(DevMonIo *self)
|
||||
{
|
||||
const gboolean low_data =
|
||||
!ril_devmon_ds_tethering_on(self->connman) &&
|
||||
!ril_devmon_ds_charging(self->charger) &&
|
||||
!ril_devmon_ds_display_on(self->display);
|
||||
|
||||
if (self->low_data != low_data) {
|
||||
self->low_data = low_data;
|
||||
DBG_(self, "Low data is%s expected", low_data ? "" : " not");
|
||||
if (self->low_data_supported) {
|
||||
grilio_channel_cancel_request(self->io,
|
||||
self->low_data_req_id, FALSE);
|
||||
self->low_data_req_id =
|
||||
ril_devmon_ds_io_send_device_state(self,
|
||||
LOW_DATA_EXPECTED, low_data,
|
||||
ril_devmon_ds_io_low_data_state_sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
ofono_cell_info_set_update_interval(self->cell_info,
|
||||
(ril_devmon_ds_display_on(self->display) &&
|
||||
(ril_devmon_ds_charging(self->charger) ||
|
||||
ril_devmon_ds_battery_ok(self->battery))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_connman_cb(struct ril_connman *connman,
|
||||
enum ril_connman_property property, void *user_data)
|
||||
{
|
||||
ril_devmon_ds_io_update_low_data((DevMonIo *)user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_update_charging(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ds_io_cast(devmon_io);
|
||||
|
||||
ril_connman_remove_all_handlers(self->connman, self->connman_event_id);
|
||||
ril_connman_unref(self->connman);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->low_data_req_id, FALSE);
|
||||
grilio_channel_cancel_request(self->io, self->charging_req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
ofono_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ds_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct ofono_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ds = ril_devmon_ds_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ds_io_free;
|
||||
self->low_data_supported = TRUE;
|
||||
self->charging_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = ofono_cell_info_ref(cell_info);
|
||||
|
||||
self->connman = ril_connman_ref(ds->connman);
|
||||
self->connman_event_id[CONNMAN_EVENT_VALID] =
|
||||
ril_connman_add_property_changed_handler(self->connman,
|
||||
RIL_CONNMAN_PROPERTY_VALID,
|
||||
ril_devmon_ds_io_connman_cb, self);
|
||||
self->connman_event_id[CONNMAN_EVENT_TETHERING] =
|
||||
ril_connman_add_property_changed_handler(self->connman,
|
||||
RIL_CONNMAN_PROPERTY_TETHERING,
|
||||
ril_devmon_ds_io_connman_cb, self);
|
||||
|
||||
self->battery = mce_battery_ref(ds->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ds_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ds_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ds->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ds_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ds_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ds->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ds_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ds_io_display_cb, self);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ds->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ds->cell_info_interval_long_ms;
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_update_charging(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ds_cast(devmon);
|
||||
|
||||
ril_connman_unref(self->connman);
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ds_free;
|
||||
self->pub.start_io = ril_devmon_ds_start_io;
|
||||
self->connman = ril_connman_new();
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
enum ril_devmon_ss_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ss_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ss_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ss {
|
||||
struct ril_devmon pub;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ss_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ofono_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
gboolean display_on;
|
||||
gboolean screen_state_supported;
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMonIo;
|
||||
|
||||
inline static DevMon *ril_devmon_ss_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
inline static DevMonIo *ril_devmon_ss_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ss_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ss_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static gboolean ril_devmon_ss_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_state_sent(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
/* This is a permanent failure */
|
||||
DBG("RIL_REQUEST_SCREEN_STATE is not supported");
|
||||
self->screen_state_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_send_screen_state(DevMonIo *self)
|
||||
{
|
||||
/*
|
||||
* RIL_REQUEST_SCREEN_STATE (deprecated on 2017-01-10)
|
||||
*
|
||||
* ((int *)data)[0] is == 1 for "Screen On"
|
||||
* ((int *)data)[0] is == 0 for "Screen Off"
|
||||
*/
|
||||
if (self->screen_state_supported) {
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
self->display_on);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
self->req_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SCREEN_STATE, ril_devmon_ss_io_state_sent,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
ofono_cell_info_set_update_interval(self->cell_info,
|
||||
(self->display_on && (ril_devmon_ss_charging(self->charger) ||
|
||||
ril_devmon_ss_battery_ok(self->battery))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
const gboolean display_on = ril_devmon_ss_display_on(display);
|
||||
|
||||
if (self->display_on != display_on) {
|
||||
self->display_on = display_on;
|
||||
ril_devmon_ss_io_send_screen_state(self);
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ss_io_cast(devmon_io);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
ofono_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ss_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct ofono_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ss = ril_devmon_ss_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ss_io_free;
|
||||
self->screen_state_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = ofono_cell_info_ref(cell_info);
|
||||
|
||||
self->battery = mce_battery_ref(ss->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ss_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ss_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ss->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ss_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ss_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ss->display);
|
||||
self->display_on = ril_devmon_ss_display_on(self->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ss_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ss_io_display_cb, self);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ss->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ss->cell_info_interval_long_ms;
|
||||
|
||||
ril_devmon_ss_io_send_screen_state(self);
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ss_cast(devmon);
|
||||
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ss_free;
|
||||
self->pub.start_io = ril_devmon_ss_start_io;
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC
|
||||
*
|
||||
* 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#define RIL_UR_ENABLE_ALL (RIL_UR_SIGNAL_STRENGTH | \
|
||||
RIL_UR_FULL_NETWORK_STATE | \
|
||||
RIL_UR_DATA_CALL_DORMANCY_CHANGED)
|
||||
|
||||
enum ril_devmon_ur_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ur_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ur_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ur {
|
||||
struct ril_devmon pub;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ur_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ofono_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
gboolean display_on;
|
||||
gboolean unsol_filter_supported;
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMonIo;
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
|
||||
|
||||
inline static DevMon *ril_devmon_ur_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
inline static DevMonIo *ril_devmon_ur_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ur_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ur_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static gboolean ril_devmon_ur_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_unsol_response_filter_sent(GRilIoChannel *io,
|
||||
int status, const void *data, guint len,
|
||||
void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
/* This is a permanent failure */
|
||||
DBG_(self, "Unsolicited response filter is not supported");
|
||||
self->unsol_filter_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_set_unsol_response_filter(DevMonIo *self)
|
||||
{
|
||||
if (self->unsol_filter_supported) {
|
||||
const gint32 value = self->display_on ? RIL_UR_ENABLE_ALL : 0;
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, value);
|
||||
|
||||
DBG_(self, "Setting unsolicited response filter: %u", value);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
self->req_id =
|
||||
grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
|
||||
ril_devmon_ur_io_unsol_response_filter_sent,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
ofono_cell_info_set_update_interval(self->cell_info,
|
||||
(self->display_on && (ril_devmon_ur_charging(self->charger) ||
|
||||
ril_devmon_ur_battery_ok(self->battery))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
const gboolean display_on = ril_devmon_ur_display_on(display);
|
||||
|
||||
if (self->display_on != display_on) {
|
||||
self->display_on = display_on;
|
||||
ril_devmon_ur_io_set_unsol_response_filter(self);
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ur_io_cast(devmon_io);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
ofono_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ur_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct ofono_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ur = ril_devmon_ur_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ur_io_free;
|
||||
self->unsol_filter_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = ofono_cell_info_ref(cell_info);
|
||||
|
||||
self->battery = mce_battery_ref(ur->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ur_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ur_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ur->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ur_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ur_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ur->display);
|
||||
self->display_on = ril_devmon_ur_display_on(self->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ur_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ur_io_display_cb, self);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ur->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ur->cell_info_interval_long_ms;
|
||||
|
||||
ril_devmon_ur_io_set_unsol_response_filter(self);
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ur_cast(devmon);
|
||||
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ur_free;
|
||||
self->pub.start_io = ril_devmon_ur_start_io;
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_inotify.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
|
||||
typedef GObjectClass RilEccListClass;
|
||||
typedef struct ril_ecclist RilEccList;
|
||||
|
||||
struct ril_ecclist_priv {
|
||||
struct ofono_sim *sim;
|
||||
GUtilInotifyWatchCallback *dir_watch;
|
||||
GUtilInotifyWatchCallback *file_watch;
|
||||
char *dir;
|
||||
char *path;
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum ril_ecclist_signal {
|
||||
SIGNAL_LIST_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_LIST_CHANGED_NAME "ril-ecclist-changed"
|
||||
|
||||
static guint ril_ecclist_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||
#define RIL_ECCLIST_TYPE (ril_ecclist_get_type())
|
||||
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_ECCLIST_TYPE, RilEccList))
|
||||
|
||||
static char **ril_ecclist_parse(const char *content)
|
||||
{
|
||||
char **ptr;
|
||||
char **list = NULL;
|
||||
guint i;
|
||||
|
||||
/*
|
||||
* Some MediaTek devices use ECC,CAT;ECC,CAT kind of syntax
|
||||
*/
|
||||
if (strchr(content, ';')) {
|
||||
list = g_strsplit(content, ";", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
char* comma;
|
||||
|
||||
*ptr = g_strstrip(*ptr);
|
||||
|
||||
/* Strip service category */
|
||||
comma = strchr(*ptr, ',');
|
||||
if (comma) {
|
||||
*comma = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The right ECC,ECC syntax is handled here */
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
gutil_strv_sort(list, TRUE);
|
||||
|
||||
/* Remove empty strings (those are at the beginning after sorting) */
|
||||
while (list[0] && !list[0][0]) {
|
||||
list = gutil_strv_remove_at(list, 0, TRUE);
|
||||
}
|
||||
|
||||
/* Remove duplicates */
|
||||
for (i = 0; list[i] && list[i+1]; i++) {
|
||||
while (list[i+1] && !strcmp(list[i], list[i+1])) {
|
||||
list = gutil_strv_remove_at(list, i+1, TRUE);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
char **list = NULL;
|
||||
|
||||
if (g_file_test(priv->path, G_FILE_TEST_EXISTS)) {
|
||||
gsize len = 0;
|
||||
gchar *content = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (g_file_get_contents(priv->path, &content, &len, &error)) {
|
||||
DBG("%s = %s", priv->name, content);
|
||||
list = ril_ecclist_parse(content);
|
||||
} else {
|
||||
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
g_free (content);
|
||||
} else {
|
||||
DBG("%s doesn't exist", priv->path);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void ril_ecclist_update(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
char **list = ril_ecclist_read(self);
|
||||
|
||||
if (!gutil_strv_equal(self->list, list)) {
|
||||
DBG("%s changed", priv->name);
|
||||
g_strfreev(self->list);
|
||||
self->list = list;
|
||||
g_signal_emit(self, ril_ecclist_signals
|
||||
[SIGNAL_LIST_CHANGED], 0);
|
||||
} else {
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
guint cookie, const char *name, void *user_data)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
ril_ecclist_update(self);
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
DBG("file %s is gone", priv->path);
|
||||
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||
priv->file_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
guint cookie, const char *name, void *user_data)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(user_data);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
DBG("0x%04x %s", mask, name);
|
||||
if (!priv->file_watch && !g_strcmp0(name, priv->name)) {
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
DBG("%swatching %s", priv->file_watch ? "" : "not ",
|
||||
priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
DBG("%s is gone", priv->dir);
|
||||
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||
priv->dir_watch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *self,
|
||||
ril_ecclist_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_LIST_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_ecclist_remove_handler(struct ril_ecclist *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_ecclist *ril_ecclist_new(const char *path)
|
||||
{
|
||||
if (path) {
|
||||
struct ril_ecclist *self = g_object_new(RIL_ECCLIST_TYPE, 0);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", path);
|
||||
priv->path = g_strdup(path);
|
||||
priv->name = g_path_get_basename(path);
|
||||
priv->dir = g_path_get_dirname(path);
|
||||
priv->dir_watch = gutil_inotify_watch_callback_new(priv->dir,
|
||||
IN_MODIFY|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|
|
||||
IN_CREATE|IN_DELETE_SELF|IN_CLOSE_WRITE,
|
||||
ril_ecclist_dir_changed, self);
|
||||
if (priv->dir_watch) {
|
||||
DBG("watching %s", priv->dir);
|
||||
}
|
||||
|
||||
self->list = ril_ecclist_read(self);
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
if (priv->file_watch) {
|
||||
DBG("watching %s", priv->path);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_ECCLIST(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_ecclist_unref(struct ril_ecclist *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_ECCLIST(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ecclist_init(struct ril_ecclist *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_ECCLIST_TYPE,
|
||||
struct ril_ecclist_priv);
|
||||
}
|
||||
|
||||
static void ril_ecclist_dispose(GObject *object)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
if (priv->dir_watch) {
|
||||
gutil_inotify_watch_callback_free(priv->dir_watch);
|
||||
priv->dir_watch = NULL;
|
||||
}
|
||||
|
||||
if (priv->file_watch) {
|
||||
gutil_inotify_watch_callback_free(priv->file_watch);
|
||||
priv->file_watch = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(ril_ecclist_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_ecclist_finalize(GObject *object)
|
||||
{
|
||||
struct ril_ecclist *self = RIL_ECCLIST(object);
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
|
||||
GASSERT(!priv->dir_watch);
|
||||
GASSERT(!priv->file_watch);
|
||||
g_free(priv->dir);
|
||||
g_free(priv->path);
|
||||
g_free(priv->name);
|
||||
g_strfreev(self->list);
|
||||
|
||||
G_OBJECT_CLASS(ril_ecclist_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_ecclist_class_init(RilEccListClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_ecclist_dispose;
|
||||
object_class->finalize = ril_ecclist_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_ecclist_priv));
|
||||
ril_ecclist_signals[SIGNAL_LIST_CHANGED] =
|
||||
g_signal_new(SIGNAL_LIST_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_ECCLIST_H
|
||||
#define RIL_ECCLIST_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_ecclist_priv;
|
||||
|
||||
struct ril_ecclist {
|
||||
GObject object;
|
||||
struct ril_ecclist_priv *priv;
|
||||
char **list;
|
||||
};
|
||||
|
||||
typedef void (*ril_ecclist_cb_t)(struct ril_ecclist *ecc, void *arg);
|
||||
|
||||
struct ril_ecclist *ril_ecclist_new(const char *path);
|
||||
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *ecc);
|
||||
void ril_ecclist_unref(struct ril_ecclist *ecc);
|
||||
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *ecc,
|
||||
ril_ecclist_cb_t cb, void *arg);
|
||||
void ril_ecclist_remove_handler(struct ril_ecclist *ecc, gulong id);
|
||||
|
||||
#endif /* RIL_ECCLIST_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_netreg.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/misc.h>
|
||||
|
||||
/*
|
||||
* This module is the ofono_gprs_driver implementation for rilmodem.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* 1. ofono_gprs_suspend/resume() are not used by this module, as
|
||||
* the concept of suspended GPRS is not exposed by RILD.
|
||||
*
|
||||
* 2. ofono_gprs_bearer_notify() is never called as RILD does not
|
||||
* expose an unsolicited event equivalent to +CPSB ( see 27.007
|
||||
* 7.29 ), and the tech values returned by REQUEST_DATA/VOICE
|
||||
* _REGISTRATION requests do not match the values defined for
|
||||
* <AcT> in the +CPSB definition. Note, the values returned by
|
||||
* the *REGISTRATION commands are aligned with those defined by
|
||||
* +CREG ( see 27.003 7.2 ).
|
||||
*/
|
||||
|
||||
struct ril_gprs {
|
||||
struct ofono_gprs *gprs;
|
||||
struct ril_modem *md;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean attached;
|
||||
int max_cids;
|
||||
enum ofono_netreg_status registration_status;
|
||||
guint register_id;
|
||||
gulong network_event_id;
|
||||
gulong data_event_id;
|
||||
guint set_attached_id;
|
||||
};
|
||||
|
||||
struct ril_gprs_cbd {
|
||||
struct ril_gprs *gd;
|
||||
ofono_gprs_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_gprs_cbd_free g_free
|
||||
|
||||
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
|
||||
{
|
||||
return ofono ? ofono_gprs_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
|
||||
|
||||
cbd->gd = gd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static enum ofono_netreg_status ril_gprs_fix_registration_status(
|
||||
struct ril_gprs *gd, enum ofono_netreg_status status)
|
||||
{
|
||||
if (!ril_data_allowed(gd->data)) {
|
||||
return OFONO_NETREG_STATUS_NOT_REGISTERED;
|
||||
} else {
|
||||
/* TODO: need a way to make sure that SPDI information has
|
||||
* already been read from the SIM (i.e. sim_spdi_read_cb in
|
||||
* network.c has been called) */
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
|
||||
return ril_netreg_check_if_really_roaming(netreg, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
|
||||
{
|
||||
const enum ofono_netreg_status status =
|
||||
ril_gprs_fix_registration_status(gd, gd->network->data.status);
|
||||
|
||||
if (gd->registration_status != status) {
|
||||
ofono_info("data reg changed %d -> %d (%s), attached %d",
|
||||
gd->registration_status, status,
|
||||
ofono_netreg_status_to_string(status),
|
||||
gd->attached);
|
||||
gd->registration_status = status;
|
||||
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
|
||||
{
|
||||
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
|
||||
gd->attached);
|
||||
if (!ril_data_allowed(gd->data) && gd->attached) {
|
||||
gd->attached = FALSE;
|
||||
if (gd->gprs) {
|
||||
ofono_gprs_detached_notify(gd->gprs);
|
||||
}
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_gprs_cbd *cbd = user_data;
|
||||
struct ril_gprs *gd = cbd->gd;
|
||||
|
||||
GASSERT(gd->set_attached_id);
|
||||
gd->set_attached_id = 0;
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
|
||||
ofono_gprs_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
if (ril_data_allowed(gd->data) || !attached) {
|
||||
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
gd->attached = attached;
|
||||
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_gprs_set_attached_cb,
|
||||
ril_gprs_cbd_new(gd, cb, data),
|
||||
ril_gprs_cbd_free);
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
GASSERT(gd->data == data);
|
||||
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
|
||||
if (!gd->set_attached_id) {
|
||||
ril_gprs_check_data_allowed(gd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
const struct ril_registration_state *data = &net->data;
|
||||
|
||||
GASSERT(gd->network == net);
|
||||
if (data->max_calls > gd->max_cids) {
|
||||
DBG("Setting max cids to %d", data->max_calls);
|
||||
gd->max_cids = data->max_calls;
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ril_gprs_data_update_registration_state(gd);
|
||||
}
|
||||
|
||||
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
|
||||
ofono_gprs_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
struct ofono_error error;
|
||||
const enum ofono_netreg_status status = gd->attached ?
|
||||
gd->registration_status : OFONO_NETREG_STATUS_NOT_REGISTERED;
|
||||
|
||||
DBG("%d (%s)", status, ofono_netreg_status_to_string(status));
|
||||
cb(ril_error_ok(&error), status, data);
|
||||
}
|
||||
|
||||
static gboolean ril_gprs_register(gpointer user_data)
|
||||
{
|
||||
struct ril_gprs *gd = user_data;
|
||||
|
||||
gd->register_id = 0;
|
||||
gd->network_event_id = ril_network_add_data_state_changed_handler(
|
||||
gd->network, ril_gprs_data_registration_state_changed, gd);
|
||||
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
|
||||
ril_gprs_allow_data_changed, gd);
|
||||
gd->registration_status = ril_gprs_fix_registration_status(gd,
|
||||
gd->network->data.status);
|
||||
|
||||
gd->max_cids = gd->network->data.max_calls;
|
||||
if (gd->max_cids > 0) {
|
||||
DBG("Setting max cids to %d", gd->max_cids);
|
||||
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
|
||||
}
|
||||
|
||||
ofono_gprs_register(gd->gprs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs *gd = g_new0(struct ril_gprs, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
gd->md = modem;
|
||||
gd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
gd->q = grilio_queue_new(gd->io);
|
||||
gd->data = ril_data_ref(modem->data);
|
||||
gd->network = ril_network_ref(modem->network);
|
||||
gd->gprs = gprs;
|
||||
ofono_gprs_set_data(gprs, gd);
|
||||
|
||||
/* ofono crashes if we register right away */
|
||||
gd->register_id = g_idle_add(ril_gprs_register, gd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_remove(struct ofono_gprs *gprs)
|
||||
{
|
||||
struct ril_gprs *gd = ril_gprs_get_data(gprs);
|
||||
|
||||
DBG("%s", ril_modem_get_path(gd->md));
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
if (gd->set_attached_id) {
|
||||
g_source_remove(gd->set_attached_id);
|
||||
}
|
||||
|
||||
if (gd->register_id) {
|
||||
g_source_remove(gd->register_id);
|
||||
}
|
||||
|
||||
ril_network_remove_handler(gd->network, gd->network_event_id);
|
||||
ril_network_unref(gd->network);
|
||||
|
||||
ril_data_remove_handler(gd->data, gd->data_event_id);
|
||||
ril_data_unref(gd->data);
|
||||
|
||||
grilio_channel_unref(gd->io);
|
||||
grilio_queue_cancel_all(gd->q, FALSE);
|
||||
grilio_queue_unref(gd->q);
|
||||
g_free(gd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_driver ril_gprs_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_probe,
|
||||
.remove = ril_gprs_remove,
|
||||
.set_attached = ril_gprs_set_attached,
|
||||
.attached_status = ril_gprs_registration_status,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,645 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_netreg.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/mtu-limit.h>
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||
|
||||
#define MAX_MMS_MTU 1280
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_request *req;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct ril_gprs_context {
|
||||
struct ofono_gprs_context *gc;
|
||||
struct ril_modem *modem;
|
||||
struct ril_network *network;
|
||||
struct ril_data *data;
|
||||
guint active_ctx_cid;
|
||||
gulong calls_changed_id;
|
||||
struct ofono_mtu_limit *mtu_limit;
|
||||
struct ril_data_call *active_call;
|
||||
struct ril_gprs_context_call activate;
|
||||
struct ril_gprs_context_call deactivate;
|
||||
};
|
||||
|
||||
static inline struct ril_gprs_context *ril_gprs_context_get_data(
|
||||
struct ofono_gprs_context *gprs)
|
||||
{
|
||||
return ofono_gprs_context_get_data(gprs);
|
||||
}
|
||||
|
||||
static char *ril_gprs_context_netmask(const char *bits)
|
||||
{
|
||||
if (bits) {
|
||||
int nbits = atoi(bits);
|
||||
if (nbits > 0 && nbits < 33) {
|
||||
const char* str;
|
||||
struct in_addr in;
|
||||
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
|
||||
((1u << nbits)-1) << (32-nbits));
|
||||
str = inet_ntoa(in);
|
||||
if (str) {
|
||||
return g_strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ril_gprs_context_address_family(const char *addr)
|
||||
{
|
||||
if (strchr(addr, ':')) {
|
||||
return AF_INET6;
|
||||
} else if (strchr(addr, '.')) {
|
||||
return AF_INET;
|
||||
} else {
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = NULL;
|
||||
}
|
||||
if (gcd->calls_changed_id) {
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id = 0;
|
||||
}
|
||||
if (gcd->mtu_limit) {
|
||||
ofono_mtu_limit_free(gcd->mtu_limit);
|
||||
gcd->mtu_limit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
if (call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (ofono_gprs_context_get_type(gcd->gc) ==
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
/*
|
||||
* Some MMS providers have a problem with MTU
|
||||
* greater than 1280. Let's be safe.
|
||||
*/
|
||||
if (!gcd->mtu_limit) {
|
||||
gcd->mtu_limit =
|
||||
ofono_mtu_limit_new(MAX_MMS_MTU);
|
||||
}
|
||||
}
|
||||
ofono_mtu_limit_set_ifname(gcd->mtu_limit, call->ifname);
|
||||
ril_data_call_grab(gcd->data, call->cid, gcd);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
if (gcd->deactivate.req) {
|
||||
struct ril_gprs_context_call deact = gcd->deactivate;
|
||||
|
||||
/*
|
||||
* Complete the deactivate request. We need to
|
||||
* clear gcd->deactivate first because cancelling
|
||||
* the deactivation request will probably result
|
||||
* in ril_gprs_context_deactivate_primary_cb() being
|
||||
* invoked with GRILIO_CANCELLED status. And we don't
|
||||
* want to fail the disconnect request because this
|
||||
* is a success (we wanted to disconnect the data
|
||||
* call and it's gone).
|
||||
*
|
||||
* Additionally, we need to make sure that we don't
|
||||
* complete the same request twice - that would crash
|
||||
* the core.
|
||||
*/
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
ril_data_request_cancel(deact.req);
|
||||
if (deact.cb) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Deactivated data call");
|
||||
deact.cb(ril_error_ok(&error), deact.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gcd->active_ctx_cid != CTX_ID_NONE) {
|
||||
guint id = gcd->active_ctx_cid;
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
DBG("ofono context %u deactivated", id);
|
||||
ofono_gprs_context_deactivated(gcd->gc, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_address(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const char *ip_addr = NULL;
|
||||
char *ip_mask = NULL;
|
||||
const char *ipv6_addr = NULL;
|
||||
unsigned char ipv6_prefix_length = 0;
|
||||
char *tmp_ip_addr = NULL;
|
||||
char *tmp_ipv6_addr = NULL;
|
||||
char * const *list = call->addresses;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n && (!ipv6_addr || !ip_addr); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
tmp_ip_addr = g_strndup(addr, len);
|
||||
ip_addr = tmp_ip_addr;
|
||||
ip_mask = ril_gprs_context_netmask(s+1);
|
||||
} else {
|
||||
ip_addr = addr;
|
||||
}
|
||||
if (!ip_mask) {
|
||||
ip_mask = g_strdup("255.255.255.0");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_addr) {
|
||||
const char* s = strstr(addr, "/");
|
||||
if (s) {
|
||||
const gsize len = s - addr;
|
||||
const int prefix = atoi(s + 1);
|
||||
tmp_ipv6_addr = g_strndup(addr, len);
|
||||
ipv6_addr = tmp_ipv6_addr;
|
||||
if (prefix >= 0 && prefix <= 128) {
|
||||
ipv6_prefix_length = prefix;
|
||||
}
|
||||
} else {
|
||||
ipv6_addr = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_address(gc, ip_addr, TRUE);
|
||||
ofono_gprs_context_set_ipv4_netmask(gc, ip_mask);
|
||||
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr);
|
||||
ofono_gprs_context_set_ipv6_prefix_length(gc, ipv6_prefix_length);
|
||||
|
||||
if (!ip_addr && !ipv6_addr) {
|
||||
ofono_error("GPRS context: No IP address");
|
||||
}
|
||||
|
||||
/* Allocate temporary strings */
|
||||
g_free(ip_mask);
|
||||
g_free(tmp_ip_addr);
|
||||
g_free(tmp_ipv6_addr);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
const char *ip_gw = NULL;
|
||||
const char *ipv6_gw = NULL;
|
||||
char * const *list = call->gateways;
|
||||
const int n = gutil_strv_length(list);
|
||||
int i;
|
||||
|
||||
/* Pick 1 gw for each protocol*/
|
||||
for (i = 0; i < n && (!ipv6_gw || !ip_gw); i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_gw) ip_gw = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_gw) ipv6_gw = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
typedef void (*ofono_gprs_context_list_setter_t)(struct ofono_gprs_context *gc,
|
||||
const char **list);
|
||||
|
||||
static void ril_gprs_context_set_servers(struct ofono_gprs_context *gc,
|
||||
char * const *list, ofono_gprs_context_list_setter_t set_ipv4,
|
||||
ofono_gprs_context_list_setter_t set_ipv6)
|
||||
{
|
||||
int i;
|
||||
const char **ip_list = NULL, **ip_ptr = NULL;
|
||||
const char **ipv6_list = NULL, **ipv6_ptr = NULL;
|
||||
const int n = gutil_strv_length(list);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_ptr) {
|
||||
ip_list = g_new0(const char *, n - i + 1);
|
||||
ip_ptr = ip_list;
|
||||
}
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_ptr) {
|
||||
ipv6_list = g_new0(const char *, n - i + 1);
|
||||
ipv6_ptr = ipv6_list;
|
||||
}
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_ipv4(gc, ip_list);
|
||||
set_ipv6(gc, ipv6_list);
|
||||
|
||||
g_free(ip_list);
|
||||
g_free(ipv6_list);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->dnses,
|
||||
ofono_gprs_context_set_ipv4_dns_servers,
|
||||
ofono_gprs_context_set_ipv6_dns_servers);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->pcscf,
|
||||
ofono_gprs_context_set_ipv4_proxy_cscf,
|
||||
ofono_gprs_context_set_ipv6_proxy_cscf);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
#define DATA_CALL_IFNAME_CHANGED (0x01)
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_PCSCF_CHANGED (0x10)
|
||||
#define DATA_CALL_ALL_CHANGED (0x1f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
{
|
||||
if (!c1 && !c2) {
|
||||
return 0;
|
||||
} else if (c1 && c2) {
|
||||
int changes = 0;
|
||||
|
||||
if (g_strcmp0(c1->ifname, c2->ifname)) {
|
||||
changes |= DATA_CALL_IFNAME_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->addresses, c2->addresses)) {
|
||||
changes |= DATA_CALL_ADDRESS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->gateways, c2->gateways)) {
|
||||
changes |= DATA_CALL_GATEWAY_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->dnses, c2->dnses)) {
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->pcscf, c2->pcscf)) {
|
||||
changes |= DATA_CALL_PCSCF_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
{
|
||||
struct ril_gprs_context *gcd = arg;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
|
||||
/*
|
||||
* gcd->active_call can't be NULL here because this callback
|
||||
* is only registered when we have the active call and released
|
||||
* when active call is dropped.
|
||||
*/
|
||||
struct ril_data_call *prev_call = gcd->active_call;
|
||||
const struct ril_data_call *call =
|
||||
ril_data_call_find(data->data_calls, prev_call->cid);
|
||||
int change = 0;
|
||||
|
||||
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
|
||||
/* Compare it against the last known state */
|
||||
change = ril_gprs_context_data_call_change(call, prev_call);
|
||||
} else {
|
||||
ofono_error("Clearing active context");
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
call = NULL;
|
||||
}
|
||||
|
||||
if (!call) {
|
||||
/* We are not interested */
|
||||
return;
|
||||
} else if (!change) {
|
||||
DBG("call %u didn't change", call->cid);
|
||||
return;
|
||||
} else {
|
||||
DBG("call %u changed", call->cid);
|
||||
}
|
||||
|
||||
/*
|
||||
* prev_call points to the previous active call, and it will
|
||||
* be deallocated at the end of the this function. Clear the
|
||||
* gcd->active_call pointer so that we don't deallocate it twice.
|
||||
*/
|
||||
gcd->active_call = NULL;
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
|
||||
if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_info("data call status: %d", call->status);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_IFNAME_CHANGED) {
|
||||
DBG("interface changed");
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_ADDRESS_CHANGED) {
|
||||
DBG("address changed");
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_GATEWAY_CHANGED) {
|
||||
DBG("gateway changed");
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_DNS_CHANGED) {
|
||||
DBG("name server(s) changed");
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_PCSCF_CHANGED) {
|
||||
DBG("P-CSCF changed");
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
int ril_status, const struct ril_data_call *call,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
struct ofono_gprs_context *gc = gcd->gc;
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_data;
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("GPRS context: Reply failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
} else if (!call) {
|
||||
ofono_error("Unexpected data call failure");
|
||||
} else if (call->status != PDP_FAIL_NONE) {
|
||||
ofono_error("Unexpected data call status %d", call->status);
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
error.error = call->status;
|
||||
} else if (!call->ifname) {
|
||||
/* Must have interface */
|
||||
ofono_error("GPRS context: No interface");
|
||||
} else {
|
||||
ofono_info("setting up data call");
|
||||
|
||||
GASSERT(!gcd->calls_changed_id);
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
gcd->calls_changed_id =
|
||||
ril_data_add_calls_changed_handler(gcd->data,
|
||||
ril_gprs_context_call_list_changed, gcd);
|
||||
|
||||
ril_gprs_context_set_active_call(gcd, call);
|
||||
ofono_gprs_context_set_interface(gc, call->ifname);
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
}
|
||||
|
||||
cb = gcd->activate.cb;
|
||||
cb_data = gcd->activate.data;
|
||||
GASSERT(gcd->activate.req);
|
||||
memset(&gcd->activate, 0, sizeof(gcd->activate));
|
||||
|
||||
if (cb) {
|
||||
cb(&error, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
|
||||
const struct ofono_gprs_primary_context *ctx,
|
||||
ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
|
||||
const enum ofono_netreg_status rs = ofono_netreg_get_status(netreg);
|
||||
|
||||
/* Let's make sure that we aren't connecting when roaming not allowed */
|
||||
if (rs == OFONO_NETREG_STATUS_ROAMING) {
|
||||
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
|
||||
if (!ofono_gprs_get_roaming_allowed(gprs) &&
|
||||
ril_netreg_check_if_really_roaming(netreg, rs) ==
|
||||
OFONO_NETREG_STATUS_ROAMING) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Can't activate context %u (roaming)",
|
||||
ctx->cid);
|
||||
cb(ril_error_failure(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Activating context: %u", ctx->cid);
|
||||
GASSERT(!gcd->activate.req);
|
||||
GASSERT(ctx->cid != CTX_ID_NONE);
|
||||
|
||||
gcd->active_ctx_cid = ctx->cid;
|
||||
gcd->activate.cb = cb;
|
||||
gcd->activate.data = data;
|
||||
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
|
||||
ofono_gprs_context_get_assigned_type(gc),
|
||||
ril_gprs_context_activate_primary_cb, gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
|
||||
int ril_status, void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
|
||||
/*
|
||||
* Data call list may change before the completion of the deactivate
|
||||
* request, in that case ril_gprs_context_set_disconnected will be
|
||||
* invoked and gcd->deactivate.req will be NULL.
|
||||
*/
|
||||
if (gcd->deactivate.req) {
|
||||
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
|
||||
gpointer cb_data = gcd->deactivate.data;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
GASSERT(gcd->active_call);
|
||||
ofono_info("Deactivated data call");
|
||||
} else {
|
||||
ofono_error("Deactivate failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
if (cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(ril_error_ok(&error), cb_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure we are in the disconnected state */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
unsigned int id, ofono_gprs_context_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
GASSERT(gcd->active_ctx_cid == id);
|
||||
ofono_info("Deactivating context: %u", id);
|
||||
|
||||
if (gcd->active_call && gcd->active_ctx_cid == id) {
|
||||
gcd->deactivate.cb = cb;
|
||||
gcd->deactivate.data = data;
|
||||
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
|
||||
gcd->active_call->cid,
|
||||
ril_gprs_context_deactivate_primary_cb, gcd);
|
||||
} else if (cb) {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
|
||||
unsigned int id)
|
||||
{
|
||||
DBG("%u", id);
|
||||
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
|
||||
}
|
||||
|
||||
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_gprs_context *gcd = g_new0(struct ril_gprs_context, 1);
|
||||
|
||||
DBG("");
|
||||
gcd->gc = gc;
|
||||
gcd->modem = modem;
|
||||
gcd->network = ril_network_ref(modem->network);
|
||||
gcd->data = ril_data_ref(modem->data);
|
||||
gcd->active_ctx_cid = CTX_ID_NONE;
|
||||
ofono_gprs_context_set_data(gc, gcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
{
|
||||
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
|
||||
|
||||
DBG("");
|
||||
ofono_gprs_context_set_data(gc, NULL);
|
||||
|
||||
if (gcd->activate.req) {
|
||||
/*
|
||||
* The core has already completed its pending D-Bus
|
||||
* request, invoking the completion callback will
|
||||
* cause libdbus to panic.
|
||||
*/
|
||||
ril_data_request_detach(gcd->activate.req);
|
||||
ril_data_request_cancel(gcd->activate.req);
|
||||
}
|
||||
|
||||
if (gcd->deactivate.req) {
|
||||
/* Let it complete but we won't be around to be notified. */
|
||||
ril_data_request_detach(gcd->deactivate.req);
|
||||
} else if (gcd->active_call) {
|
||||
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
|
||||
ril_data_unref(gcd->data);
|
||||
ril_network_unref(gcd->network);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
ofono_mtu_limit_free(gcd->mtu_limit);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
const struct ofono_gprs_context_driver ril_gprs_context_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_gprs_context_probe,
|
||||
.remove = ril_gprs_context_remove,
|
||||
.activate_primary = ril_gprs_context_activate_primary,
|
||||
.deactivate_primary = ril_gprs_context_deactivate_primary,
|
||||
.detach_shutdown = ril_gprs_context_detach_shutdown,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_LOG_H
|
||||
#define RIL_LOG_H
|
||||
|
||||
#define GLOG_MODULE_NAME ril_log
|
||||
#include <gutil_log.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#endif /* RIL_LOG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,572 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/message-waiting.h>
|
||||
#include <ofono/cell-info.h>
|
||||
#include <ofono/sim-auth.h>
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
POWERED_OFF,
|
||||
POWERED_ON,
|
||||
POWERING_OFF
|
||||
};
|
||||
|
||||
enum ril_modem_online_state {
|
||||
OFFLINE,
|
||||
GOING_ONLINE,
|
||||
ONLINE,
|
||||
GOING_OFFLINE
|
||||
};
|
||||
|
||||
enum ril_modem_watch_event {
|
||||
WATCH_IMSI,
|
||||
WATCH_ICCID,
|
||||
WATCH_SIM_STATE,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_modem_online_request {
|
||||
const char *name;
|
||||
ofono_modem_online_cb_t cb;
|
||||
struct ril_modem_data *md;
|
||||
void *data;
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
struct ofono_watch *watch;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
char* last_known_iccid;
|
||||
char* reset_iccid;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
gulong radio_state_event_id;
|
||||
|
||||
struct ril_modem_online_request set_online;
|
||||
struct ril_modem_online_request set_offline;
|
||||
};
|
||||
|
||||
#define RADIO_POWER_TAG(md) (md)
|
||||
|
||||
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
|
||||
|
||||
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
{
|
||||
struct ril_modem_data *md = ofono_modem_get_data(o);
|
||||
GASSERT(md->modem.ofono == o);
|
||||
return md;
|
||||
}
|
||||
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *m)
|
||||
{
|
||||
return (m && m->ofono) ? ofono_modem_get_sim(m->ofono) : NULL;
|
||||
}
|
||||
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *m)
|
||||
{
|
||||
return (m && m->ofono) ? ofono_modem_get_gprs(m->ofono) : NULL;
|
||||
}
|
||||
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *m)
|
||||
{
|
||||
return (m && m->ofono) ? ofono_modem_get_netreg(m->ofono) : NULL;
|
||||
}
|
||||
|
||||
static inline struct ofono_radio_settings *ril_modem_radio_settings(
|
||||
struct ril_modem *modem)
|
||||
{
|
||||
return (modem && modem->ofono) ?
|
||||
ofono_modem_get_radio_settings(modem->ofono) : NULL;
|
||||
}
|
||||
|
||||
void ril_modem_delete(struct ril_modem *md)
|
||||
{
|
||||
if (md && md->ofono) {
|
||||
ofono_modem_remove(md->ofono);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_done(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_modem_online_cb_t cb = req->cb;
|
||||
void *data = req->data;
|
||||
|
||||
req->cb = NULL;
|
||||
req->data = NULL;
|
||||
DBG_(req->md, "%s", req->name);
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
}
|
||||
|
||||
ril_modem_online_request_done(req);
|
||||
}
|
||||
|
||||
static void ril_modem_update_online_state(struct ril_modem_data *md)
|
||||
{
|
||||
switch (md->modem.radio->state) {
|
||||
case RADIO_STATE_ON:
|
||||
DBG_(md, "online");
|
||||
ril_modem_online_request_ok(&md->set_online);
|
||||
break;
|
||||
|
||||
case RADIO_STATE_OFF:
|
||||
case RADIO_STATE_UNAVAILABLE:
|
||||
DBG_(md, "offline");
|
||||
ril_modem_online_request_ok(&md->set_offline);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
|
||||
md->power_state == POWERING_OFF) {
|
||||
md->power_state = POWERED_OFF;
|
||||
if (md->modem.ofono) {
|
||||
ofono_modem_set_powered(md->modem.ofono, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_request_timeout(gpointer data)
|
||||
{
|
||||
struct ril_modem_online_request *req = data;
|
||||
|
||||
GASSERT(req->timeout_id);
|
||||
req->timeout_id = 0;
|
||||
DBG_(req->md, "%s", req->name);
|
||||
ril_modem_online_request_done(req);
|
||||
ril_modem_update_online_state(req->md);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_modem_online_check(gpointer data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->online_check_id);
|
||||
md->online_check_id = 0;
|
||||
ril_modem_update_online_state(md);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
{
|
||||
if (!md->online_check_id) {
|
||||
md->online_check_id = g_idle_add(ril_modem_online_check, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *m = &md->modem;
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
|
||||
if (md->watch->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!rs) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} else if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
/* ofono core may remove radio settings atom internally */
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.radio == radio);
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
static void ril_modem_iccid_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
if (watch->iccid) {
|
||||
g_free(md->last_known_iccid);
|
||||
md->last_known_iccid = g_strdup(watch->iccid);
|
||||
DBG_(md, "%s", md->last_known_iccid);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_sim_state_cb(struct ofono_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
|
||||
|
||||
GASSERT(md->watch == watch);
|
||||
if (state == OFONO_SIM_STATE_RESETTING) {
|
||||
g_free(md->reset_iccid);
|
||||
md->reset_iccid = md->last_known_iccid;
|
||||
md->last_known_iccid = NULL;
|
||||
DBG_(md, "%s is resetting", md->reset_iccid);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (md->modem.config.enable_voicecall) {
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
ril_modem_radio_state_cb, md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ofono_gprs *gprs;
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
guint i;
|
||||
static const enum ofono_gprs_context_type ap_types[] = {
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET,
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS,
|
||||
OFONO_GPRS_CONTEXT_TYPE_IMS
|
||||
};
|
||||
|
||||
/* Create a context for each type */
|
||||
for (i = 0; i < G_N_ELEMENTS(ap_types); i++) {
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
|
||||
ofono_gprs_context_set_type(gc, ap_types[i]);
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
}
|
||||
|
||||
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_message_waiting_register(ofono_message_waiting_create(modem));
|
||||
if (md->modem.config.enable_stk) {
|
||||
if (!md->reset_iccid ||
|
||||
g_strcmp0(md->reset_iccid, md->watch->iccid)) {
|
||||
/* This SIM was never reset */
|
||||
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
} else {
|
||||
ofono_warn("Disabling STK after SIM reset");
|
||||
}
|
||||
}
|
||||
if (md->modem.config.enable_cbs) {
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
ofono_sim_auth_create(modem);
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_netmon_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
|
||||
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ril_radio *radio = md->modem.radio;
|
||||
struct ril_modem_online_request *req;
|
||||
|
||||
DBG("%s going %sline", ofono_modem_get_path(modem),
|
||||
online ? "on" : "off");
|
||||
|
||||
ril_radio_set_online(radio, online);
|
||||
if (online) {
|
||||
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
} else {
|
||||
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
}
|
||||
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
if (req->timeout_id) {
|
||||
g_source_remove(req->timeout_id);
|
||||
}
|
||||
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
|
||||
ril_modem_online_request_timeout, req);
|
||||
ril_modem_schedule_online_check(md);
|
||||
}
|
||||
|
||||
static int ril_modem_enable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->power_state = POWERED_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ril_modem_disable(struct ofono_modem *modem)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
|
||||
md->power_state = POWERING_OFF;
|
||||
return -EINPROGRESS;
|
||||
} else {
|
||||
md->power_state = POWERED_OFF;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_modem_probe(struct ofono_modem *modem)
|
||||
{
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
ofono_modem_set_data(ofono, NULL);
|
||||
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_set_online(modem->radio, FALSE);
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_set_online(modem->radio, FALSE);
|
||||
ril_radio_unref(modem->radio);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
|
||||
ofono_watch_remove_all_handlers(md->watch, md->watch_event_id);
|
||||
ofono_watch_unref(md->watch);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
|
||||
if (md->set_online.timeout_id) {
|
||||
g_source_remove(md->set_online.timeout_id);
|
||||
}
|
||||
|
||||
if (md->set_offline.timeout_id) {
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_vendor_unref(modem->vendor);
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
ofono_cell_info_unref(modem->cell_info);
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
g_free(md->last_known_iccid);
|
||||
g_free(md->reset_iccid);
|
||||
g_free(md->ecclist_file);
|
||||
g_free(md->log_prefix);
|
||||
g_free(md->imeisv);
|
||||
g_free(md->imei);
|
||||
g_free(md);
|
||||
}
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct ofono_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
/*
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(imei);
|
||||
|
||||
/* Copy config */
|
||||
modem->config = *config;
|
||||
modem->imei = md->imei = g_strdup(imei);
|
||||
modem->imeisv = md->imeisv = g_strdup(imeisv);
|
||||
modem->log_prefix = log_prefix; /* No need to strdup */
|
||||
modem->ecclist_file = ecclist_file; /* No need to strdup */
|
||||
md->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->vendor = ril_vendor_ref(vendor);
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
modem->sim_settings = ril_sim_settings_ref(settings);
|
||||
modem->cell_info = ofono_cell_info_ref(cell_info);
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
md->watch = ofono_watch_new(path);
|
||||
md->last_known_iccid = g_strdup(md->watch->iccid);
|
||||
|
||||
md->watch_event_id[WATCH_IMSI] =
|
||||
ofono_watch_add_imsi_changed_handler(md->watch,
|
||||
ril_modem_imsi_cb, md);
|
||||
md->watch_event_id[WATCH_ICCID] =
|
||||
ofono_watch_add_iccid_changed_handler(md->watch,
|
||||
ril_modem_iccid_cb, md);
|
||||
md->watch_event_id[WATCH_SIM_STATE] =
|
||||
ofono_watch_add_sim_state_changed_handler(md->watch,
|
||||
ril_modem_sim_state_cb, md);
|
||||
|
||||
md->set_online.name = "online";
|
||||
md->set_online.md = md;
|
||||
md->set_offline.name = "offline";
|
||||
md->set_offline.md = md;
|
||||
ofono_modem_set_data(ofono, md);
|
||||
err = ofono_modem_register(ofono);
|
||||
if (!err) {
|
||||
GASSERT(io->connected);
|
||||
if (config->radio_power_cycle) {
|
||||
ril_radio_power_cycle(modem->radio);
|
||||
}
|
||||
|
||||
/*
|
||||
* ofono_modem_reset sets Powered to TRUE without
|
||||
* issuing PropertyChange signal.
|
||||
*/
|
||||
ofono_modem_set_powered(modem->ofono, FALSE);
|
||||
ofono_modem_set_powered(modem->ofono, TRUE);
|
||||
md->power_state = POWERED_ON;
|
||||
|
||||
/*
|
||||
* With some RIL implementations, querying available
|
||||
* band modes causes some magic Android properties to
|
||||
* appear.
|
||||
*/
|
||||
if (config->query_available_band_mode) {
|
||||
grilio_queue_send_request(md->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
|
||||
}
|
||||
|
||||
ril_modem_update_radio_settings(md);
|
||||
return modem;
|
||||
} else {
|
||||
ofono_error("Error %d registering %s",
|
||||
err, RILMODEM_DRIVER);
|
||||
|
||||
/*
|
||||
* If ofono_modem_register() failed, then
|
||||
* ofono_modem_remove() won't invoke
|
||||
* ril_modem_remove() callback.
|
||||
*/
|
||||
ril_modem_remove(ofono);
|
||||
}
|
||||
|
||||
ofono_modem_remove(ofono);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct ofono_modem_driver ril_modem_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_modem_probe,
|
||||
.remove = ril_modem_remove,
|
||||
.enable = ril_modem_enable,
|
||||
.disable = ril_modem_disable,
|
||||
.pre_sim = ril_modem_pre_sim,
|
||||
.post_sim = ril_modem_post_sim,
|
||||
.post_online = ril_modem_post_online,
|
||||
.set_online = ril_modem_set_online
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,329 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sim-mnclength.h>
|
||||
#include <ofono/cell-info.h>
|
||||
|
||||
struct ril_netmon {
|
||||
struct ofono_netmon *netmon;
|
||||
struct ofono_cell_info *cell_info;
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
/* This number must be in sync with ril_netmon_notify_ofono: */
|
||||
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
|
||||
|
||||
struct ril_netmon_ofono_param {
|
||||
enum ofono_netmon_info type;
|
||||
int value;
|
||||
};
|
||||
|
||||
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
|
||||
{
|
||||
return ofono ? ofono_netmon_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
{
|
||||
s_mcc[0] = 0;
|
||||
s_mnc[0] = 0;
|
||||
|
||||
if (mcc >= 0 && mcc <= 999) {
|
||||
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
|
||||
if (mnc >= 0 && mnc <= 999) {
|
||||
const int mnclen =
|
||||
ofono_sim_mnclength_get_mnclength_mccmnc(mcc,
|
||||
mnc);
|
||||
const char *format[] = { "%d", "%02d", "%03d" };
|
||||
const char *fmt = (mnclen > 0 &&
|
||||
mnclen <= G_N_ELEMENTS(format)) ?
|
||||
format[mnclen - 1] : format[0];
|
||||
snprintf(s_mnc, OFONO_MAX_MNC_LENGTH + 1, fmt, mnc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
|
||||
enum ofono_netmon_cell_type type, int mcc, int mnc,
|
||||
struct ril_netmon_ofono_param *params, int nparams)
|
||||
{
|
||||
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
int i;
|
||||
|
||||
/* Better not to push uninitialized data to the stack ... */
|
||||
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
|
||||
params[i].type = OFONO_NETMON_INFO_INVALID;
|
||||
params[i].value = OFONO_CELL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
|
||||
ofono_netmon_serving_cell_notify(netmon, type,
|
||||
OFONO_NETMON_INFO_MCC, s_mcc,
|
||||
OFONO_NETMON_INFO_MNC, s_mnc,
|
||||
params[0].type, params[0].value,
|
||||
params[1].type, params[1].value,
|
||||
params[2].type, params[2].value,
|
||||
params[3].type, params[3].value,
|
||||
params[4].type, params[4].value,
|
||||
params[5].type, params[5].value,
|
||||
params[6].type, params[6].value,
|
||||
params[7].type, params[7].value,
|
||||
OFONO_NETMON_INFO_INVALID);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
const struct ofono_cell_info_gsm *gsm)
|
||||
{
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
if (gsm->lac != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||
params[n].value = gsm->lac;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->cid != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = gsm->cid;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->arfcn != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||
params[n].value = gsm->arfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->signalStrength != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = gsm->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (gsm->bitErrorRate != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_BER;
|
||||
params[n].value = gsm->bitErrorRate;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
|
||||
gsm->mcc, gsm->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
const struct ofono_cell_info_wcdma *wcdma)
|
||||
{
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
if (wcdma->lac != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_LAC;
|
||||
params[n].value = wcdma->lac;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->cid != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = wcdma->cid;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->psc != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_PSC;
|
||||
params[n].value = wcdma->psc;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->uarfcn != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_ARFCN;
|
||||
params[n].value = wcdma->uarfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->signalStrength != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = wcdma->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wcdma->bitErrorRate != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_BER;
|
||||
params[n].value = wcdma->bitErrorRate;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
|
||||
wcdma->mcc, wcdma->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||
const struct ofono_cell_info_lte *lte)
|
||||
{
|
||||
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
|
||||
int n = 0;
|
||||
|
||||
if (lte->ci != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CI;
|
||||
params[n].value = lte->ci;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->earfcn != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_EARFCN;
|
||||
params[n].value = lte->earfcn;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->signalStrength != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSSI;
|
||||
params[n].value = lte->signalStrength;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->rsrp != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSRQ;
|
||||
params[n].value = lte->rsrp;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->rsrq != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_RSRP;
|
||||
params[n].value = lte->rsrq;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->cqi != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_CQI;
|
||||
params[n].value = lte->cqi;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (lte->timingAdvance != OFONO_CELL_INVALID_VALUE) {
|
||||
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
|
||||
params[n].value = lte->timingAdvance;
|
||||
n++;
|
||||
}
|
||||
|
||||
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
|
||||
lte->mcc, lte->mnc, params, n);
|
||||
}
|
||||
|
||||
static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
ofono_netmon_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||
const ofono_cell_ptr *cells = nm->cell_info->cells;
|
||||
struct ofono_error error;
|
||||
|
||||
if (cells) {
|
||||
const ofono_cell_ptr *ptr;
|
||||
|
||||
for (ptr = cells; *ptr; ptr++) {
|
||||
const struct ofono_cell *cell = *ptr;
|
||||
|
||||
if (cell->registered) {
|
||||
switch (cell->type) {
|
||||
case OFONO_CELL_TYPE_GSM:
|
||||
ril_netmon_notify_gsm(netmon,
|
||||
&cell->info.gsm);
|
||||
break;
|
||||
case OFONO_CELL_TYPE_WCDMA:
|
||||
ril_netmon_notify_wcdma(netmon,
|
||||
&cell->info.wcdma);
|
||||
break;
|
||||
case OFONO_CELL_TYPE_LTE:
|
||||
ril_netmon_notify_lte(netmon,
|
||||
&cell->info.lte);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static gboolean ril_netmon_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netmon *nm = user_data;
|
||||
|
||||
GASSERT(nm->register_id);
|
||||
nm->register_id = 0;
|
||||
ofono_netmon_register(nm->netmon);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
int ret;
|
||||
|
||||
if (modem->cell_info) {
|
||||
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
|
||||
|
||||
nm->cell_info = ofono_cell_info_ref(modem->cell_info);
|
||||
nm->netmon = netmon;
|
||||
|
||||
ofono_netmon_set_data(netmon, nm);
|
||||
nm->register_id = g_idle_add(ril_netmon_register, nm);
|
||||
ret = 0;
|
||||
} else {
|
||||
DBG("%s no", modem->log_prefix ? modem->log_prefix : "");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
DBG("%s %d", modem->log_prefix ? modem->log_prefix : "", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||
{
|
||||
struct ril_netmon *nm = ril_netmon_get_data(netmon);
|
||||
|
||||
DBG("");
|
||||
ofono_netmon_set_data(netmon, NULL);
|
||||
|
||||
if (nm->register_id > 0) {
|
||||
g_source_remove(nm->register_id);
|
||||
}
|
||||
|
||||
ofono_cell_info_unref(nm->cell_info);
|
||||
g_slice_free(struct ril_netmon, nm);
|
||||
}
|
||||
|
||||
const struct ofono_netmon_driver ril_netmon_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_netmon_probe,
|
||||
.remove = ril_netmon_remove,
|
||||
.request_update = ril_netmon_request_update,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,726 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_netreg.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/watch.h>
|
||||
#include <ofono/gprs-provision.h>
|
||||
|
||||
#define REGISTRATION_MAX_RETRIES (2)
|
||||
|
||||
enum ril_netreg_events {
|
||||
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
|
||||
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
|
||||
NETREG_RIL_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_netreg_network_events {
|
||||
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
|
||||
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
|
||||
NETREG_NETWORK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean network_selection_manual_0;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
struct ofono_watch *watch;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
struct ril_vendor *vendor;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
guint notify_id;
|
||||
guint current_operator_id;
|
||||
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||
int network_selection_timeout;
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
struct ril_netreg *nd;
|
||||
union {
|
||||
ofono_netreg_status_cb_t status;
|
||||
ofono_netreg_operator_cb_t operator;
|
||||
ofono_netreg_operator_list_cb_t operator_list;
|
||||
ofono_netreg_register_cb_t reg;
|
||||
ofono_netreg_strength_cb_t strength;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_netreg_cbd_free g_free
|
||||
|
||||
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
|
||||
{
|
||||
return ofono ? ofono_netreg_get_data(ofono) : NULL;
|
||||
}
|
||||
|
||||
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
|
||||
void *cb, void *data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = g_new0(struct ril_netreg_cbd, 1);
|
||||
|
||||
cbd->nd = nd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
enum ofono_netreg_status ril_netreg_check_if_really_roaming
|
||||
(struct ofono_netreg *netreg, enum ofono_netreg_status status)
|
||||
{
|
||||
if (status == OFONO_NETREG_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);
|
||||
|
||||
if (ofono_netreg_spdi_lookup(netreg, net_mcc, net_mnc)) {
|
||||
ofono_info("not roaming based on spdi");
|
||||
return OFONO_NETREG_STATUS_REGISTERED;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
|
||||
{
|
||||
return (nd && nd->netreg) ?
|
||||
ril_netreg_check_if_really_roaming(nd->netreg, status) :
|
||||
status;
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_status_notify_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
|
||||
DBG_(nd, "");
|
||||
GASSERT(nd->notify_id);
|
||||
nd->notify_id = 0;
|
||||
ofono_netreg_status_notify(nd->netreg,
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
/* Coalesce multiple notifications into one */
|
||||
if (nd->notify_id) {
|
||||
DBG_(nd, "notification aready queued");
|
||||
} else {
|
||||
DBG_(nd, "queuing notification");
|
||||
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
|
||||
ofono_netreg_status_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
const struct ril_registration_state *reg = &nd->network->voice;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(nd, "");
|
||||
cb(ril_error_ok(&error),
|
||||
ril_netreg_check_status(nd, reg->status),
|
||||
reg->lac, reg->ci, reg->access_tech, data);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_current_operator_cb(void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(nd, "");
|
||||
GASSERT(nd->current_operator_id);
|
||||
nd->current_operator_id = 0;
|
||||
|
||||
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
/*
|
||||
* Calling ofono_netreg_status_notify() may result in
|
||||
* ril_netreg_current_operator() being invoked even if one
|
||||
* is already pending. Since ofono core doesn't associate
|
||||
* any context with individual calls, we can safely assume
|
||||
* that such a call essentially cancels the previous one.
|
||||
*/
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_netreg_current_operator_cb,
|
||||
ril_netreg_cbd_new(nd, cb, data),
|
||||
ril_netreg_cbd_free);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_strange(const struct ofono_network_operator *op,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
gsize mcclen;
|
||||
|
||||
if (sim && op->status != OFONO_OPERATOR_STATUS_CURRENT) {
|
||||
const char *spn = ofono_sim_get_spn(sim);
|
||||
const char *mcc = ofono_sim_get_mcc(sim);
|
||||
const char *mnc = ofono_sim_get_mnc(sim);
|
||||
|
||||
if (spn && mcc && mnc && !strcmp(op->name, spn) &&
|
||||
(strcmp(op->mcc, mcc) || strcmp(op->mnc, mnc))) {
|
||||
/*
|
||||
* Status is not "current", SPN matches the SIM, but
|
||||
* MCC and/or MNC don't (e.g. Sony Xperia X where all
|
||||
* operators could be reported with the same name
|
||||
* which equals SPN).
|
||||
*/
|
||||
DBG("%s %s%s (sim spn?)", op->name, op->mcc, op->mnc);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
mcclen = strlen(op->mcc);
|
||||
if (!strncmp(op->name, op->mcc, mcclen) &&
|
||||
!strcmp(op->name + mcclen, op->mnc)) {
|
||||
/* Some MediaTek RILs only report numeric operator name */
|
||||
DBG("%s %s%s (numeric?)", op->name, op->mcc, op->mnc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_process_operators(struct ril_netreg *nd,
|
||||
struct ofono_network_operator *ops, int nops)
|
||||
{
|
||||
if (nd->replace_strange_oper) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nops; i++) {
|
||||
struct ofono_network_operator *op = ops + i;
|
||||
struct ofono_gprs_provision_data *prov = NULL;
|
||||
int np = 0;
|
||||
|
||||
if (ril_netreg_strange(op, nd->watch->sim) &&
|
||||
ofono_gprs_provision_get_settings(op->mcc,
|
||||
op->mnc, NULL, &prov, &np)) {
|
||||
/* Use the first entry */
|
||||
if (np > 0 && prov->provider_name &&
|
||||
prov->provider_name[0]) {
|
||||
DBG("%s %s%s -> %s", op->name, op->mcc,
|
||||
op->mnc, prov->provider_name);
|
||||
strncpy(op->name, prov->provider_name,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
}
|
||||
ofono_gprs_provision_free_settings(prov, np);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
struct ofono_network_operator *list;
|
||||
struct ofono_error error;
|
||||
int noperators = 0, i;
|
||||
GRilIoParser rilp;
|
||||
gboolean ok = TRUE;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("Failed to retrive the list of operators: %s",
|
||||
ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* Number of operators at the list (4 strings for every operator) */
|
||||
grilio_parser_get_int32(&rilp, &noperators);
|
||||
GASSERT(!(noperators % 4));
|
||||
noperators /= 4;
|
||||
ofono_info("noperators = %d", noperators);
|
||||
|
||||
list = g_new0(struct ofono_network_operator, noperators);
|
||||
for (i = 0; i < noperators && ok; i++) {
|
||||
struct ofono_network_operator *op = list + i;
|
||||
char *lalpha = grilio_parser_get_utf8(&rilp);
|
||||
char *salpha = grilio_parser_get_utf8(&rilp);
|
||||
char *numeric = grilio_parser_get_utf8(&rilp);
|
||||
char *status = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
/* Try to use long by default */
|
||||
if (lalpha) {
|
||||
strncpy(op->name, lalpha,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else if (salpha) {
|
||||
strncpy(op->name, salpha,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
} else {
|
||||
op->name[0] = 0;
|
||||
}
|
||||
|
||||
/* Set the proper status */
|
||||
op->status = OFONO_OPERATOR_STATUS_UNKNOWN;
|
||||
if (status) {
|
||||
if (!strcmp(status, "available")) {
|
||||
op->status = OFONO_OPERATOR_STATUS_AVAILABLE;
|
||||
} else if (!strcmp(status, "current")) {
|
||||
op->status = OFONO_OPERATOR_STATUS_CURRENT;
|
||||
} else if (!strcmp(status, "forbidden")) {
|
||||
op->status = OFONO_OPERATOR_STATUS_FORBIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
op->tech = -1;
|
||||
ok = ril_parse_mcc_mnc(numeric, op);
|
||||
if (ok) {
|
||||
if (op->tech < 0) {
|
||||
op->tech = nd->network->voice.access_tech;
|
||||
}
|
||||
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||
op->mcc, op->mnc, status);
|
||||
} else {
|
||||
DBG("failed to parse operator list");
|
||||
}
|
||||
|
||||
g_free(lalpha);
|
||||
g_free(salpha);
|
||||
g_free(numeric);
|
||||
g_free(status);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ril_netreg_process_operators(nd, list, noperators);
|
||||
cb(ril_error_ok(&error), noperators, list, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
}
|
||||
|
||||
g_free(list);
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators(struct ofono_netreg *netreg,
|
||||
ofono_netreg_operator_list_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
|
||||
ril_netreg_list_operators_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_netreg_register_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb.reg;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("registration failed, ril result %d", status);
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_set_register_auto(struct ril_netreg *nd,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_request_set_timeout(req, nd->network_selection_timeout);
|
||||
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_query_register_auto_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb.reg;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
gint32 net_mode;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, NULL) /* Array length */ &&
|
||||
grilio_parser_get_int32(&rilp, &net_mode) &&
|
||||
net_mode == RIL_NETWORK_SELECTION_MODE_AUTO) {
|
||||
struct ofono_error error;
|
||||
ofono_info("nw selection is already auto");
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ril_netreg_set_register_auto(cbd->nd, cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_netreg_register_auto(struct ofono_netreg *netreg,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
|
||||
ril_netreg_query_register_auto_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
const char *mcc, const char *mnc,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
const char *suffix = nd->network_selection_manual_0 ? "+0" : "";
|
||||
|
||||
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
|
||||
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
|
||||
grilio_request_set_timeout(req, nd->network_selection_timeout);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
|
||||
{
|
||||
const int min_qdbm = 4 * nd->signal_strength_dbm_weak; /* 4*dBm */
|
||||
const int max_qdbm = 4 * nd->signal_strength_dbm_strong; /* 4*dBm */
|
||||
|
||||
return (qdbm <= min_qdbm) ? 1 :
|
||||
(qdbm >= max_qdbm) ? 100 :
|
||||
(100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
|
||||
const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
struct ril_vendor_signal_strength signal;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
|
||||
gint32 rsrp = 0, tdscdma_dbm = 0;
|
||||
|
||||
/* Apply default parsing algorithm */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.gsm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.lte);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
|
||||
/* The rest is considered optional */
|
||||
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* timingAdv */
|
||||
/* TD_SCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &tdscdma_dbm) &&
|
||||
/* RSCP range: 25 to 120 dBm per 3GPP TS 25.123 */
|
||||
tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||
signal.qdbm = -4 * tdscdma_dbm;
|
||||
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
|
||||
signal.qdbm = -4 * rsrp;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("gw: %d, lte: %d, qdbm: %d", signal.gsm, signal.lte, signal.qdbm);
|
||||
|
||||
/* Return the first valid one */
|
||||
|
||||
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
|
||||
* RSRP value. If we've got zero, don't report it just yet. */
|
||||
if (signal.gsm >= 1 && signal.gsm <= 31) {
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
return (signal.gsm * 100) / 31;
|
||||
}
|
||||
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
if (signal.lte >= 0 && signal.lte <= 31) {
|
||||
return (signal.lte * 100) / 31;
|
||||
}
|
||||
|
||||
if (signal.qdbm < 0) {
|
||||
return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
|
||||
} else if (signal.gsm == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
int strength;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||
strength = ril_netreg_get_signal_strength(nd, data, len);
|
||||
DBG_(nd, "%d", strength);
|
||||
if (strength >= 0) {
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_strength_cb_t cb = cbd->cb.strength;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), ril_netreg_get_signal_strength
|
||||
(cbd->nd, data, len), cbd->data);
|
||||
} else {
|
||||
ofono_error("Failed to retrive the signal strength: %s",
|
||||
ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), -1, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength(struct ofono_netreg *netreg,
|
||||
ofono_netreg_strength_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SIGNAL_STRENGTH, ril_netreg_strength_cb,
|
||||
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
GRilIoParser rilp;
|
||||
int year, mon, mday, hour, min, sec, tzi, dst = 0;
|
||||
char tzs;
|
||||
gchar *nitz;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
nitz = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
DBG_(nd, "%s", nitz);
|
||||
|
||||
/*
|
||||
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
|
||||
* The ds part is considered optional, initialized to zero.
|
||||
*/
|
||||
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
|
||||
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
|
||||
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
|
||||
struct ofono_network_time time;
|
||||
char tz[4];
|
||||
|
||||
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
|
||||
time.utcoff = atoi(tz) * 15 * 60;
|
||||
time.dst = dst;
|
||||
time.sec = sec;
|
||||
time.min = min;
|
||||
time.hour = hour;
|
||||
time.mday = mday;
|
||||
time.mon = mon;
|
||||
time.year = 2000 + year;
|
||||
|
||||
ofono_netreg_time_notify(nd->netreg, &time);
|
||||
} else {
|
||||
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
|
||||
}
|
||||
|
||||
g_free(nitz);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_register(gpointer user_data)
|
||||
{
|
||||
struct ril_netreg *nd = user_data;
|
||||
|
||||
GASSERT(nd->timer_id);
|
||||
nd->timer_id = 0;
|
||||
ofono_netreg_register(nd->netreg);
|
||||
|
||||
/* Register for network state changes */
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
|
||||
ril_network_add_operator_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
|
||||
ril_network_add_voice_state_changed_handler(nd->network,
|
||||
ril_netreg_status_notify, nd);
|
||||
|
||||
/* Register for network time updates */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_nitz_notify,
|
||||
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
|
||||
|
||||
/* Register for signal strength changes */
|
||||
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
|
||||
grilio_channel_add_unsol_event_handler(nd->io,
|
||||
ril_netreg_strength_notify,
|
||||
RIL_UNSOL_SIGNAL_STRENGTH, nd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
|
||||
const struct ril_slot_config *config = &modem->config;
|
||||
|
||||
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
DBG_(nd, "%p", netreg);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->watch = ofono_watch_new(ril_modem_get_path(modem));
|
||||
nd->vendor = ril_vendor_ref(modem->vendor);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
nd->replace_strange_oper = config->replace_strange_oper;
|
||||
nd->network_selection_manual_0 = config->network_selection_manual_0;
|
||||
nd->signal_strength_dbm_weak = config->signal_strength_dbm_weak;
|
||||
nd->signal_strength_dbm_strong = config->signal_strength_dbm_strong;
|
||||
nd->network_selection_timeout = config->network_selection_timeout;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
|
||||
DBG_(nd, "%p", netreg);
|
||||
grilio_queue_cancel_all(nd->q, FALSE);
|
||||
ofono_netreg_set_data(netreg, NULL);
|
||||
|
||||
if (nd->timer_id > 0) {
|
||||
g_source_remove(nd->timer_id);
|
||||
}
|
||||
|
||||
if (nd->notify_id) {
|
||||
g_source_remove(nd->notify_id);
|
||||
}
|
||||
|
||||
if (nd->current_operator_id) {
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
ofono_watch_unref(nd->watch);
|
||||
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
|
||||
ril_network_unref(nd->network);
|
||||
ril_vendor_unref(nd->vendor);
|
||||
|
||||
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
|
||||
grilio_channel_unref(nd->io);
|
||||
grilio_queue_unref(nd->q);
|
||||
g_free(nd->log_prefix);
|
||||
g_free(nd);
|
||||
}
|
||||
|
||||
const struct ofono_netreg_driver ril_netreg_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_netreg_probe,
|
||||
.remove = ril_netreg_remove,
|
||||
.registration_status = ril_netreg_registration_status,
|
||||
.current_operator = ril_netreg_current_operator,
|
||||
.list_operators = ril_netreg_list_operators,
|
||||
.register_auto = ril_netreg_register_auto,
|
||||
.register_manual = ril_netreg_register_manual,
|
||||
.strength = ril_netreg_strength
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2021 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_NETREG_H
|
||||
#define RIL_NETREG_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
enum ofono_netreg_status ril_netreg_check_if_really_roaming
|
||||
(struct ofono_netreg *reg, enum ofono_netreg_status status);
|
||||
|
||||
#endif /* RIL_NETREG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_NETWORK_H
|
||||
#define RIL_NETWORK_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
struct ril_radio_caps;
|
||||
|
||||
struct ril_registration_state {
|
||||
enum ofono_netreg_status status;
|
||||
enum ofono_access_technology access_tech;
|
||||
int ril_tech;
|
||||
int max_calls;
|
||||
int lac;
|
||||
int ci;
|
||||
};
|
||||
|
||||
struct ril_network {
|
||||
GObject object;
|
||||
struct ril_network_priv *priv;
|
||||
struct ril_registration_state voice;
|
||||
struct ril_registration_state data;
|
||||
const struct ofono_network_operator *operator;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
enum ofono_radio_access_mode max_pref_mode;
|
||||
struct ril_sim_settings *settings;
|
||||
};
|
||||
|
||||
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
|
||||
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *ril_slot_config,
|
||||
struct ril_vendor *vendor);
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
void ril_network_set_radio_caps(struct ril_network *net,
|
||||
struct ril_radio_caps *caps);
|
||||
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
enum ofono_radio_access_mode ril_network_max_supported_mode
|
||||
(struct ril_network *self);
|
||||
void ril_network_query_registration_state(struct ril_network *net);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||
|
||||
#define ril_network_remove_all_handlers(net, ids) \
|
||||
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_NETWORK_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/gdbus.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/dbus-access.h>
|
||||
|
||||
#define RIL_OEM_RAW_INTERFACE "org.ofono.OemRaw"
|
||||
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
|
||||
|
||||
struct ril_oem_raw {
|
||||
GRilIoQueue *q;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
char *log_prefix;
|
||||
};
|
||||
|
||||
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||
|
||||
static void ril_oem_raw_send_done(void *msg)
|
||||
{
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DBusMessage *msg = user_data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBusMessageIter it, array;
|
||||
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_BYTE_AS_STRING, &array);
|
||||
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
|
||||
&data, len);
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
|
||||
DBG("Timed out");
|
||||
reply = ofono_dbus_error_timed_out(msg);
|
||||
} else {
|
||||
DBG("Error %s", ril_error_to_string(ril_status));
|
||||
reply = ofono_dbus_error_failed(msg);
|
||||
}
|
||||
|
||||
g_dbus_send_message(ofono_dbus_get_connection(), reply);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
void *user_data)
|
||||
{
|
||||
DBusMessageIter it;
|
||||
struct ril_oem_raw *oem = user_data;
|
||||
|
||||
if (!ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
|
||||
OFONO_DBUS_ACCESS_INTF_OEMRAW,
|
||||
OFONO_DBUS_ACCESS_OEMRAW_SEND, NULL)) {
|
||||
return ofono_dbus_error_access_denied(msg);
|
||||
}
|
||||
|
||||
dbus_message_iter_init(msg, &it);
|
||||
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
|
||||
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
|
||||
char *data;
|
||||
int data_len;
|
||||
DBusMessageIter array;
|
||||
GRilIoRequest *req;
|
||||
|
||||
/* Fetch the data */
|
||||
dbus_message_iter_recurse(&it, &array);
|
||||
dbus_message_iter_get_fixed_array(&array, &data, &data_len);
|
||||
DBG_(oem, "%d bytes", data_len);
|
||||
|
||||
/*
|
||||
* And forward it to rild. Set a timeout because rild may
|
||||
* never respond to invalid requests.
|
||||
*/
|
||||
req = grilio_request_sized_new(data_len);
|
||||
grilio_request_set_timeout(req, RIL_OEM_RAW_TIMEOUT);
|
||||
grilio_request_append_bytes(req, data, data_len);
|
||||
grilio_queue_send_request_full(oem->q, req,
|
||||
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
|
||||
ril_oem_raw_send_done, dbus_message_ref(msg));
|
||||
grilio_request_unref(req);
|
||||
return NULL;
|
||||
} else {
|
||||
DBG_(oem, "Unexpected signature");
|
||||
return ofono_dbus_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_oem_raw_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("Send",
|
||||
GDBUS_ARGS({ "request", "ay" }),
|
||||
GDBUS_ARGS({ "response", "ay" }),
|
||||
ril_oem_raw_send) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix)
|
||||
{
|
||||
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
oem->path = g_strdup(ril_modem_get_path(modem));
|
||||
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
oem->q = grilio_queue_new(ril_modem_io(modem));
|
||||
oem->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE, ril_oem_raw_methods,
|
||||
NULL, NULL, oem, NULL)) {
|
||||
ofono_modem_add_interface(modem->ofono, RIL_OEM_RAW_INTERFACE);
|
||||
return oem;
|
||||
} else {
|
||||
ofono_error("OemRaw D-Bus register failed");
|
||||
ril_oem_raw_free(oem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_oem_raw_free(struct ril_oem_raw *oem)
|
||||
{
|
||||
if (oem) {
|
||||
DBG("%s", oem->path);
|
||||
g_dbus_unregister_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
dbus_connection_unref(oem->conn);
|
||||
|
||||
grilio_queue_cancel_all(oem->q, TRUE);
|
||||
grilio_queue_unref(oem->q);
|
||||
|
||||
g_free(oem->log_prefix);
|
||||
g_free(oem->path);
|
||||
g_free(oem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_PLUGIN_H
|
||||
#define RIL_PLUGIN_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-barring.h>
|
||||
#include <ofono/call-forwarding.h>
|
||||
#include <ofono/call-settings.h>
|
||||
#include <ofono/call-volume.h>
|
||||
#include <ofono/cbs.h>
|
||||
#include <ofono/devinfo.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/phonebook.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/sim.h>
|
||||
#include <ofono/sms.h>
|
||||
#include <ofono/stk.h>
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/voicecall.h>
|
||||
#include <ofono/netmon.h>
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#define RILMODEM_DRIVER "ril"
|
||||
|
||||
struct ril_modem {
|
||||
GRilIoChannel *io;
|
||||
const char *imei;
|
||||
const char *imeisv;
|
||||
const char *log_prefix;
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct ofono_cell_info *cell_info;
|
||||
struct ril_vendor *vendor;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_slot_config config;
|
||||
};
|
||||
|
||||
struct ril_oem_raw;
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix);
|
||||
void ril_oem_raw_free(struct ril_oem_raw *raw);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct ofono_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
|
||||
|
||||
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
|
||||
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
|
||||
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
|
||||
extern const struct ofono_call_barring_driver ril_call_barring_driver;
|
||||
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
||||
extern const struct ofono_call_settings_driver ril_call_settings_driver;
|
||||
extern const struct ofono_call_volume_driver ril_call_volume_driver;
|
||||
extern const struct ofono_cbs_driver ril_cbs_driver;
|
||||
extern const struct ofono_devinfo_driver ril_devinfo_driver;
|
||||
extern const struct ofono_gprs_context_driver ril_gprs_context_driver;
|
||||
extern const struct ofono_gprs_driver ril_gprs_driver;
|
||||
extern const struct ofono_modem_driver ril_modem_driver;
|
||||
extern const struct ofono_netreg_driver ril_netreg_driver;
|
||||
extern const struct ofono_phonebook_driver ril_phonebook_driver;
|
||||
extern const struct ofono_radio_settings_driver ril_radio_settings_driver;
|
||||
extern const struct ofono_sim_driver ril_sim_driver;
|
||||
extern const struct ofono_sms_driver ril_sms_driver;
|
||||
extern const struct ofono_stk_driver ril_stk_driver;
|
||||
extern const struct ofono_ussd_driver ril_ussd_driver;
|
||||
extern const struct ofono_voicecall_driver ril_voicecall_driver;
|
||||
extern const struct ofono_netmon_driver ril_netmon_driver;
|
||||
|
||||
#endif /* RIL_PLUGIN_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,511 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2020 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.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
typedef GObjectClass RilRadioClass;
|
||||
typedef struct ril_radio RilRadio;
|
||||
|
||||
/*
|
||||
* Object states:
|
||||
*
|
||||
* 1. Idle (!pending && !retry)
|
||||
* 2. Power on/off request pending (pending)
|
||||
* 3. Power on retry has been scheduled (retry)
|
||||
*/
|
||||
struct ril_radio_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong state_event_id;
|
||||
char *log_prefix;
|
||||
GHashTable *req_table;
|
||||
guint pending_id;
|
||||
guint retry_id;
|
||||
guint state_changed_while_request_pending;
|
||||
enum ril_radio_state last_known_state;
|
||||
gboolean power_cycle;
|
||||
gboolean next_state_valid;
|
||||
gboolean next_state;
|
||||
};
|
||||
|
||||
enum ril_radio_signal {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_ONLINE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define POWER_RETRY_SECS (1)
|
||||
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
|
||||
|
||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_radio_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
|
||||
#define RIL_RADIO_TYPE (ril_radio_get_type())
|
||||
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
|
||||
|
||||
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
|
||||
!priv->power_cycle;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
|
||||
{
|
||||
return radio_state == RADIO_STATE_OFF;
|
||||
}
|
||||
|
||||
static inline gboolean ril_radio_state_on(enum ril_radio_state radio_state)
|
||||
{
|
||||
return !ril_radio_state_off(radio_state);
|
||||
}
|
||||
|
||||
static inline void ril_radio_emit_signal(struct ril_radio *self,
|
||||
enum ril_radio_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_radio_signals[id], 0);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self,
|
||||
ril_radio_power_should_be_on(self));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_cancel_retry(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->retry_id) {
|
||||
DBG_(self, "retry cancelled");
|
||||
g_source_remove(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_check_state(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!priv->pending_id) {
|
||||
gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
/* All is good, cancel pending retry if there is one */
|
||||
ril_radio_cancel_retry(self);
|
||||
} else if (priv->state_changed_while_request_pending) {
|
||||
/* Hmm... RIL's reaction was inadequate, repeat */
|
||||
ril_radio_submit_power_request(self, should_be_on);
|
||||
} else if (!priv->retry_id) {
|
||||
/* There has been no reaction so far, wait a bit */
|
||||
DBG_(self, "retry scheduled");
|
||||
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
|
||||
ril_radio_power_request_retry_cb, self);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't update public state while something is pending */
|
||||
if (!priv->pending_id && !priv->retry_id &&
|
||||
self->state != priv->last_known_state) {
|
||||
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
|
||||
ril_radio_state_to_string(priv->last_known_state));
|
||||
self->state = priv->last_known_state;
|
||||
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_done(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
priv->pending_id = 0;
|
||||
|
||||
if (priv->next_state_valid) {
|
||||
ril_radio_submit_power_request(self, priv->next_state);
|
||||
} else {
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
|
||||
if (ril_status != RIL_E_SUCCESS) {
|
||||
ofono_error("Power request failed: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
ril_radio_power_request_done(self);
|
||||
}
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
{
|
||||
/*
|
||||
* RIL_REQUEST_RADIO_POWER
|
||||
*
|
||||
* "data" is int *
|
||||
* ((int *)data)[0] is > 0 for "Radio On"
|
||||
* ((int *)data)[0] is == 0 for "Radio Off"
|
||||
*
|
||||
* "response" is NULL
|
||||
**/
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, on);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
priv->next_state_valid = FALSE;
|
||||
priv->next_state = on;
|
||||
priv->state_changed_while_request_pending = 0;
|
||||
ril_radio_cancel_retry(self);
|
||||
|
||||
GASSERT(!priv->pending_id);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
gboolean allow_repeat)
|
||||
{
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
const char *on_off = on ? "on" : "off";
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (allow_repeat || priv->next_state != on) {
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = on;
|
||||
DBG_(self, "%s (queued)", on_off);
|
||||
} else {
|
||||
DBG_(self, "%s (ignored)", on_off);
|
||||
}
|
||||
} else {
|
||||
if (ril_radio_state_on(priv->last_known_state) == on) {
|
||||
DBG_(self, "%s (already)", on_off);
|
||||
ril_radio_check_state(self);
|
||||
} else {
|
||||
DBG_(self, "%s", on_off);
|
||||
ril_radio_submit_power_request(self, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_confirm_power_on(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (!priv->next_state) {
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = TRUE;
|
||||
DBG_(self, "on (queued)");
|
||||
}
|
||||
} else {
|
||||
DBG_(self, "on");
|
||||
ril_radio_submit_power_request(self, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_cycle(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (ril_radio_state_off(priv->last_known_state)) {
|
||||
DBG_(self, "power is already off");
|
||||
GASSERT(!priv->power_cycle);
|
||||
} else if (priv->power_cycle) {
|
||||
DBG_(self, "already in progress");
|
||||
} else {
|
||||
DBG_(self, "initiated");
|
||||
priv->power_cycle = TRUE;
|
||||
if (!priv->pending_id) {
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!g_hash_table_contains(priv->req_table, tag)) {
|
||||
gboolean was_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
DBG_(self, "%p", tag);
|
||||
g_hash_table_insert(priv->req_table, tag, tag);
|
||||
if (!was_on && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_power_off(struct ril_radio *self, gpointer tag)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (g_hash_table_remove(priv->req_table, tag)) {
|
||||
DBG_(self, "%p", tag);
|
||||
if (!ril_radio_power_should_be_on(self)) {
|
||||
/* The last one turns the lights off */
|
||||
ril_radio_power_request(self, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_set_online(struct ril_radio *self, gboolean online)
|
||||
{
|
||||
if (G_LIKELY(self) && self->online != online) {
|
||||
gboolean on, was_on = ril_radio_power_should_be_on(self);
|
||||
self->online = online;
|
||||
on = ril_radio_power_should_be_on(self);
|
||||
if (was_on != on) {
|
||||
ril_radio_power_request(self, on, FALSE);
|
||||
}
|
||||
ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
|
||||
ril_radio_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_remove_handlers(struct ril_radio *self, gulong *ids, int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int radio_state;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &radio_state)) {
|
||||
return radio_state;
|
||||
} else {
|
||||
ofono_error("Error parsing radio state");
|
||||
return RADIO_STATE_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||
if (radio_state != RADIO_STATE_UNAVAILABLE) {
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
|
||||
GASSERT(!priv->pending_id || !priv->retry_id);
|
||||
|
||||
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
|
||||
DBG_(self, "switched off for power cycle");
|
||||
priv->power_cycle = FALSE;
|
||||
}
|
||||
|
||||
priv->last_known_state = radio_state;
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (ril_radio_state_on(radio_state) ==
|
||||
ril_radio_power_should_be_on(self)) {
|
||||
DBG_(self, "dropping pending request");
|
||||
/*
|
||||
* All right, the modem has switched to the
|
||||
* desired state, drop the request.
|
||||
*/
|
||||
grilio_queue_cancel_request(priv->q,
|
||||
priv->pending_id, FALSE);
|
||||
|
||||
/*
|
||||
* This will zero pending_id and call
|
||||
* ril_radio_check_state() if necesary:
|
||||
*/
|
||||
ril_radio_power_request_done(self);
|
||||
|
||||
/* We are done */
|
||||
return;
|
||||
} else {
|
||||
/* Something weird is going on */
|
||||
priv->state_changed_while_request_pending++;
|
||||
}
|
||||
}
|
||||
|
||||
ril_radio_check_state(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io)
|
||||
{
|
||||
struct ril_radio *self = g_object_new(RIL_RADIO_TYPE, NULL);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(priv->io);
|
||||
priv->log_prefix =
|
||||
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
|
||||
g_strconcat(io->name, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_radio_state_changed,
|
||||
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
|
||||
/*
|
||||
* Some RILs like to receive power off request at startup even if
|
||||
* radio is already off. Make those happy.
|
||||
*/
|
||||
ril_radio_submit_power_request(self, FALSE);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_RADIO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_radio_unref(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_RADIO(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_radio_init(struct ril_radio *self)
|
||||
{
|
||||
struct ril_radio_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_RADIO_TYPE, struct ril_radio_priv);
|
||||
self->priv = priv;
|
||||
priv->req_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void ril_radio_dispose(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->state_event_id) {
|
||||
grilio_channel_remove_handler(priv->io, priv->state_event_id);
|
||||
priv->state_event_id = 0;
|
||||
}
|
||||
if (priv->pending_id) {
|
||||
grilio_queue_cancel_request(priv->q, priv->pending_id, FALSE);
|
||||
priv->pending_id = 0;
|
||||
}
|
||||
priv->next_state_valid = FALSE;
|
||||
ril_radio_cancel_retry(self);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_radio_finalize(GObject *object)
|
||||
{
|
||||
struct ril_radio *self = RIL_RADIO(object);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
g_hash_table_unref(priv->req_table);
|
||||
G_OBJECT_CLASS(ril_radio_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_radio_class_init(RilRadioClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_radio_dispose;
|
||||
object_class->finalize = ril_radio_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
|
||||
NEW_SIGNAL(klass, STATE);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_RADIO_H
|
||||
#define RIL_RADIO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_radio {
|
||||
GObject object;
|
||||
struct ril_radio_priv *priv;
|
||||
enum ril_radio_state state;
|
||||
gboolean online;
|
||||
};
|
||||
|
||||
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
|
||||
|
||||
struct ril_radio *ril_radio_new(GRilIoChannel *io);
|
||||
struct ril_radio *ril_radio_ref(struct ril_radio *radio);
|
||||
void ril_radio_unref(struct ril_radio *radio);
|
||||
|
||||
void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
|
||||
void ril_radio_power_cycle(struct ril_radio *radio);
|
||||
void ril_radio_confirm_power_on(struct ril_radio *radio);
|
||||
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
|
||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
|
||||
ril_radio_cb_t cb, void *arg);
|
||||
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||
|
||||
#define ril_radio_remove_all_handlers(r,ids) \
|
||||
ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_RADIO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_RADIO_CAPS_H
|
||||
#define RIL_RADIO_CAPS_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_sim_settings;
|
||||
struct ril_radio_caps;
|
||||
struct ril_radio_caps_manager;
|
||||
struct ril_radio_capability;
|
||||
struct ril_radio_caps_request;
|
||||
|
||||
typedef void (*ril_radio_caps_cb_t)(struct ril_radio_caps *caps, void *arg);
|
||||
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
|
||||
void *user_data);
|
||||
|
||||
/* ril_radio_capability pointer is NULL if functionality is unsupported */
|
||||
typedef void (*ril_radio_caps_check_cb_t)
|
||||
(const struct ril_radio_capability *cap, void *user_data);
|
||||
|
||||
/* The check can be cancelled with grilio_channel_cancel_request */
|
||||
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
|
||||
void *user_data);
|
||||
|
||||
/* There should be a single ril_radio_caps_manager shared by all all modems */
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_new
|
||||
(struct ril_data_manager *dm);
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
|
||||
(struct ril_radio_caps_manager *mgr);
|
||||
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
|
||||
gulong ril_radio_caps_manager_add_tx_aborted_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
gulong ril_radio_caps_manager_add_tx_done_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
|
||||
gulong id);
|
||||
void ril_radio_caps_manager_remove_handlers(struct ril_radio_caps_manager *mgr,
|
||||
gulong *ids, int count);
|
||||
#define ril_radio_caps_manager_remove_all_handlers(mgr, ids) \
|
||||
ril_radio_caps_manager_remove_handlers(mgr, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
/* And one ril_radio_caps object per modem */
|
||||
|
||||
struct ril_radio_caps {
|
||||
struct ril_radio_caps_manager *mgr;
|
||||
enum ofono_radio_access_mode supported_modes;
|
||||
};
|
||||
|
||||
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
const char *log_prefix, GRilIoChannel *io,
|
||||
struct ofono_watch *watch,
|
||||
struct ril_data *data, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim, struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *config,
|
||||
const struct ril_radio_capability *cap);
|
||||
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_unref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_drop(struct ril_radio_caps *caps);
|
||||
gulong ril_radio_caps_add_supported_modes_handler
|
||||
(struct ril_radio_caps *caps,
|
||||
ril_radio_caps_cb_t cb, void *arg);
|
||||
void ril_radio_caps_remove_handler(struct ril_radio_caps *caps, gulong id);
|
||||
|
||||
/* Data requests */
|
||||
|
||||
struct ril_radio_caps_request *ril_radio_caps_request_new
|
||||
(struct ril_radio_caps *caps, enum ofono_radio_access_mode mode,
|
||||
enum ril_data_role role);
|
||||
void ril_radio_caps_request_free(struct ril_radio_caps_request *req);
|
||||
|
||||
#endif /* RIL_RADIO_CAPS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
struct ril_radio_settings {
|
||||
struct ofono_radio_settings *rs;
|
||||
struct ril_sim_settings *settings;
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
struct ril_radio_settings_cbd {
|
||||
struct ril_radio_settings *rsd;
|
||||
union _ofono_radio_settings_cb {
|
||||
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
|
||||
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
|
||||
ofono_radio_settings_available_rats_query_cb_t available_rats;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(rsd,fmt,args...) DBG("%s" fmt, (rsd)->log_prefix, ##args)
|
||||
|
||||
static inline struct ril_radio_settings *ril_radio_settings_get_data(
|
||||
struct ofono_radio_settings *rs)
|
||||
{
|
||||
return ofono_radio_settings_get_data(rs);
|
||||
}
|
||||
|
||||
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
|
||||
GSourceFunc fn, void *cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd;
|
||||
|
||||
cbd = g_new0(struct ril_radio_settings_cbd, 1);
|
||||
cbd->rsd = rsd;
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
|
||||
GASSERT(!rsd->source_id);
|
||||
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
fn, cbd, g_free);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_set_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_set(ril_error_ok(&error), cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
|
||||
enum ofono_radio_access_mode mode,
|
||||
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
DBG_(rsd, "%s", ofono_radio_access_mode_to_string(mode));
|
||||
ril_sim_settings_set_pref_mode(rsd->settings, mode);
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_set_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_rat_mode_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings_cbd *cbd = user_data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(rsd, "rat mode %s", ofono_radio_access_mode_to_string(mode));
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.rat_mode_query(ril_error_ok(&error), mode, cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_rat_mode_cb,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
|
||||
cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_query_available_rats(
|
||||
struct ofono_radio_settings *rs,
|
||||
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd,
|
||||
ril_radio_settings_query_available_rats_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
{
|
||||
struct ril_radio_settings *rsd = user_data;
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
ofono_radio_settings_register(rsd->rs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
|
||||
unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
|
||||
|
||||
DBG("%s", modem->log_prefix);
|
||||
rsd->rs = rs;
|
||||
rsd->settings = ril_sim_settings_ref(modem->sim_settings);
|
||||
rsd->source_id = g_idle_add(ril_radio_settings_register, rsd);
|
||||
|
||||
if (modem->log_prefix && modem->log_prefix[0]) {
|
||||
rsd->log_prefix = rsd->allocated_log_prefix =
|
||||
g_strconcat(modem->log_prefix, " ", NULL);
|
||||
} else {
|
||||
rsd->log_prefix = "";
|
||||
}
|
||||
|
||||
ofono_radio_settings_set_data(rs, rsd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
{
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
if (rsd->source_id) {
|
||||
g_source_remove(rsd->source_id);
|
||||
}
|
||||
ril_sim_settings_unref(rsd->settings);
|
||||
g_free(rsd->allocated_log_prefix);
|
||||
g_free(rsd);
|
||||
}
|
||||
|
||||
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_radio_settings_probe,
|
||||
.remove = ril_radio_settings_remove,
|
||||
.query_rat_mode = ril_radio_settings_query_rat_mode,
|
||||
.set_rat_mode = ril_radio_settings_set_rat_mode,
|
||||
.query_available_rats = ril_radio_settings_query_available_rats
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,805 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2020 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.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_queue.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
/*
|
||||
* First we wait for USIM app to get activated by itself. If that
|
||||
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
|
||||
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
|
||||
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
|
||||
*
|
||||
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
|
||||
* it sometimes breaks pretty much everything. Unfortunately, there no
|
||||
* reliable way to find out when rild expects it and when it doesn't :/
|
||||
*/
|
||||
#define UICC_SUBSCRIPTION_START_MS (5000)
|
||||
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
||||
|
||||
/* SIM I/O idle timeout is measured in the number of idle loops.
|
||||
* When active SIM I/O is going on, the idle loop count very rarely
|
||||
* exceeds 1 between the requests, so 10 is more than enough. Idle
|
||||
* loop is actually more accurate criteria than a timeout because
|
||||
* it doesn't depend that much on the system load. */
|
||||
#define SIM_IO_IDLE_LOOPS (10)
|
||||
|
||||
typedef GObjectClass RilSimCardClass;
|
||||
typedef struct ril_sim_card RilSimCard;
|
||||
|
||||
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;
|
||||
guint sub_req_id;
|
||||
guint sub_start_timer;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
guint sim_io_idle_id;
|
||||
guint sim_io_idle_count;
|
||||
GHashTable* sim_io_pending;
|
||||
};
|
||||
|
||||
enum ril_sim_card_signal {
|
||||
SIGNAL_STATUS_RECEIVED,
|
||||
SIGNAL_STATUS_CHANGED,
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_APP_CHANGED,
|
||||
SIGNAL_SIM_IO_ACTIVE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
|
||||
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
|
||||
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
|
||||
#define SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME "ril-simcard-sim-io-active-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 NEW_SIGNAL(klass,name) NEW_SIGNAL_(klass,name##_CHANGED)
|
||||
#define NEW_SIGNAL_(klass,name) \
|
||||
ril_sim_card_signals[SIGNAL_##name] = \
|
||||
g_signal_new(SIGNAL_##name##_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define RIL_SIMCARD_STATE_CHANGED (0x01)
|
||||
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
|
||||
|
||||
static 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_tx_start(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRILIO_TRANSACTION_STATE tx_state =
|
||||
grilio_queue_transaction_state(priv->q);
|
||||
|
||||
if (tx_state == GRILIO_TRANSACTION_NONE) {
|
||||
tx_state = grilio_queue_transaction_start(priv->q);
|
||||
DBG("status tx for slot %u %s", self->slot,
|
||||
(tx_state == GRILIO_TRANSACTION_STARTED) ?
|
||||
"started" : "starting");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_tx_check(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (grilio_queue_transaction_state(priv->q) !=
|
||||
GRILIO_TRANSACTION_NONE) {
|
||||
const struct ril_sim_card_status *status = self->status;
|
||||
|
||||
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
/* Transaction (if there is any) is finished when
|
||||
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
|
||||
* complete or get dropped */
|
||||
if (!priv->status_req_id && !priv->sub_req_id &&
|
||||
status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
DBG("status tx for slot %u finished",
|
||||
self->slot);
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
} else {
|
||||
DBG("status tx for slot %u cancelled", self->slot);
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sub_start_timer) {
|
||||
/* Don't need this timer anymore */
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
priv->sub_start_timer = 0;
|
||||
}
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
* removed from the list of pending requests) */
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
}
|
||||
ril_sim_card_tx_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
const void* data, guint len, void* user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
GASSERT(status == GRILIO_STATUS_OK);
|
||||
GASSERT(priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
DBG("UICC subscription OK for slot %u", self->slot);
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
guint code;
|
||||
|
||||
DBG("%u,%d,%u", self->slot, app_index, sub_id);
|
||||
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, RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
|
||||
grilio_request_set_retry(req, 0, -1);
|
||||
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
||||
code = (priv->io->ril_version <= 9 &&
|
||||
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION;
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
* removed from the list of pending requests) */
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
}
|
||||
|
||||
/* Don't allow any requests other that GET_SIM_STATUS until
|
||||
* we are done with the subscription */
|
||||
ril_sim_card_tx_start(self);
|
||||
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
||||
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
|
||||
{
|
||||
int i, selected_app = -1;
|
||||
|
||||
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;
|
||||
ril_sim_card_subscription_done(self);
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0 && !self->priv->sub_start_timer) {
|
||||
ril_sim_card_subscribe(self, app_index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app_index = -1;
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
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 gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
DBG("%u", self->slot);
|
||||
GASSERT(priv->sub_start_timer);
|
||||
priv->sub_start_timer = 0;
|
||||
ril_sim_card_update_app(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
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;
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED &&
|
||||
status->card_state == RIL_CARDSTATE_PRESENT) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* SIM card has just appeared, give it some time to
|
||||
* activate the USIM app
|
||||
*/
|
||||
if (priv->sub_start_timer) {
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
}
|
||||
DBG("started subscription timeout for slot %u",
|
||||
self->slot);
|
||||
priv->sub_start_timer =
|
||||
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
|
||||
ril_sim_card_sub_start_timeout, self);
|
||||
}
|
||||
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_update_app(self);
|
||||
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) {
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
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 = RIL_SIMCARD(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);
|
||||
}
|
||||
}
|
||||
|
||||
ril_sim_card_tx_check(self);
|
||||
}
|
||||
|
||||
void ril_sim_card_reset(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_card_status *status =
|
||||
g_new0(struct ril_sim_card_status, 1);
|
||||
|
||||
/* Simulate removal and re-submit the SIM status query */
|
||||
status->card_state = RIL_CARDSTATE_ABSENT;
|
||||
status->gsm_umts_index = -1;
|
||||
status->cdma_index = -1;
|
||||
status->ims_index = -1;
|
||||
ril_sim_card_update_status(self, status);
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->status_req_id) {
|
||||
/* Retry right away, don't wait for retry
|
||||
* timeout to expire */
|
||||
grilio_channel_retry_request(priv->io,
|
||||
priv->status_req_id);
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
/* Start the transaction to not allow any other
|
||||
* requests to interfere with SIM status query */
|
||||
ril_sim_card_tx_start(self);
|
||||
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_update_sim_io_active(struct ril_sim_card *self)
|
||||
{
|
||||
/* SIM I/O is considered active for certain period of time after
|
||||
* the last request has completed. That's because SIM_IO requests
|
||||
* are usually submitted in large quantities and quick succession.
|
||||
* Some RILs don't like being bothered while they are doing SIM I/O
|
||||
* and some time after that too. That sucks but what else can we
|
||||
* do about it? */
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
const gboolean active = priv->sim_io_idle_id ||
|
||||
g_hash_table_size(priv->sim_io_pending);
|
||||
|
||||
if (self->sim_io_active != active) {
|
||||
self->sim_io_active = active;
|
||||
DBG("SIM I/O for slot %u is %sactive", self->slot,
|
||||
active ? "" : "in");
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_SIM_IO_ACTIVE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *self, guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(id);
|
||||
|
||||
g_hash_table_insert(priv->sim_io_pending, key, key);
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
priv->sim_io_idle_id = 0;
|
||||
priv->sim_io_idle_count = 0;
|
||||
}
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_sim_io_idle_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (++(priv->sim_io_idle_count) >= SIM_IO_IDLE_LOOPS) {
|
||||
priv->sim_io_idle_id = 0;
|
||||
priv->sim_io_idle_count = 0;
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
} else {
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *self, guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(id);
|
||||
|
||||
if (g_hash_table_remove(priv->sim_io_pending, key) &&
|
||||
!g_hash_table_size(priv->sim_io_pending)) {
|
||||
/* Reset the idle loop count */
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
priv->sim_io_idle_count = 0;
|
||||
}
|
||||
priv->sim_io_idle_id =
|
||||
g_idle_add(ril_sim_card_sim_io_idle_cb, self);
|
||||
}
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags)
|
||||
{
|
||||
struct ril_sim_card *self = g_object_new(RIL_SIMCARD_TYPE, NULL);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* We need to know the RIL version (for UICC subscription hack),
|
||||
* so we must be connected. The caller is supposed to make sure
|
||||
* that we get connected first.
|
||||
*/
|
||||
DBG("%u", slot);
|
||||
GASSERT(io->connected);
|
||||
|
||||
self->slot = slot;
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->q = grilio_queue_new(io);
|
||||
priv->flags = flags;
|
||||
|
||||
priv->event_id[EVENT_SIM_STATUS_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_sim_card_status_changed,
|
||||
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, self);
|
||||
priv->event_id[EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_sim_card_status_changed,
|
||||
RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, self);
|
||||
ril_sim_card_request_status(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIMCARD(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_unref(struct ril_sim_card *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIMCARD(self));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_sim_card_ready(struct ril_sim_card *self)
|
||||
{
|
||||
return self && self->app &&
|
||||
((self->app->app_state == RIL_APPSTATE_READY) ||
|
||||
(self->app->app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO &&
|
||||
self->app->perso_substate == RIL_PERSOSUBSTATE_READY));
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATUS_RECEIVED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATUS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *self, gulong *ids, int n)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, n);
|
||||
}
|
||||
|
||||
static void ril_sim_card_init(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_SIMCARD_TYPE, struct ril_sim_card_priv);
|
||||
|
||||
self->priv = priv;
|
||||
priv->sim_io_pending = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void ril_sim_card_dispose(GObject *object)
|
||||
{
|
||||
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;
|
||||
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
}
|
||||
if (priv->sub_start_timer) {
|
||||
g_source_remove(priv->sub_start_timer);
|
||||
}
|
||||
g_hash_table_destroy(priv->sim_io_pending);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_sim_card_status_free(self->status);
|
||||
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));
|
||||
NEW_SIGNAL_(klass,STATUS_RECEIVED);
|
||||
NEW_SIGNAL(klass,STATUS);
|
||||
NEW_SIGNAL(klass,STATE);
|
||||
NEW_SIGNAL(klass,APP);
|
||||
NEW_SIGNAL(klass,SIM_IO_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_SIM_CARD_H
|
||||
#define RIL_SIM_CARD_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.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;
|
||||
gboolean sim_io_active;
|
||||
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);
|
||||
void ril_sim_card_reset(struct ril_sim_card *sc);
|
||||
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
||||
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
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);
|
||||
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
|
||||
|
||||
/* Inline wrappers */
|
||||
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
|
||||
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
|
||||
{ return (sc && sc->app) ? sc->app->aid : NULL; }
|
||||
|
||||
#define ril_sim_card_remove_all_handlers(net, ids) \
|
||||
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_SIM_CARD_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2020 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.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define RIL_PREF_MODE_DEFAULT(self) (\
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_LTE : \
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS : \
|
||||
OFONO_RADIO_ACCESS_MODE_GSM)
|
||||
|
||||
typedef GObjectClass RilSimSettingsClass;
|
||||
typedef struct ril_sim_settings RilSimSettings;
|
||||
|
||||
enum ofono_watch_events {
|
||||
WATCH_EVENT_IMSI,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_settings_priv {
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
struct ofono_watch *watch;
|
||||
char *imsi;
|
||||
};
|
||||
|
||||
enum ril_sim_settings_signal {
|
||||
SIGNAL_IMSI_CHANGED,
|
||||
SIGNAL_PREF_MODE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-settings-imsi-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-sim-settings-pref-mode-changed"
|
||||
|
||||
static guint ril_sim_settings_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilSimSettings, ril_sim_settings, G_TYPE_OBJECT)
|
||||
#define RIL_SIM_SETTINGS_TYPE (ril_sim_settings_get_type())
|
||||
#define RIL_SIM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_SIM_SETTINGS_TYPE, RilSimSettings))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_sim_settings_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
/* Skip the leading slash from the modem path: */
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
|
||||
enum ril_sim_settings_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_sim_settings_signals[id], 0);
|
||||
}
|
||||
|
||||
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
if (G_LIKELY(self) && self->pref_mode != mode) {
|
||||
self->pref_mode = mode;
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_imsi_changed(struct ofono_watch *watch,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->imsi, watch->imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(watch->imsi);
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs)
|
||||
{
|
||||
struct ril_sim_settings *self = NULL;
|
||||
|
||||
if (G_LIKELY(path)) {
|
||||
struct ril_sim_settings_priv *priv;
|
||||
|
||||
self = g_object_new(RIL_SIM_SETTINGS_TYPE, NULL);
|
||||
priv = self->priv;
|
||||
self->techs = techs;
|
||||
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
|
||||
priv->watch = ofono_watch_new(path);
|
||||
priv->watch_event_id[WATCH_EVENT_IMSI] =
|
||||
ofono_watch_add_imsi_changed_handler(priv->watch,
|
||||
ril_sim_settings_imsi_changed, self);
|
||||
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIM_SETTINGS(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIM_SETTINGS(self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
|
||||
ril_sim_settings_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_settings_add_pref_mode_changed_handler(
|
||||
struct ril_sim_settings *self,
|
||||
ril_sim_settings_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_settings_remove_handler(struct ril_sim_settings *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
|
||||
gulong *ids, int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_init(struct ril_sim_settings *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIM_SETTINGS_TYPE,
|
||||
struct ril_sim_settings_priv);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
ofono_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
ofono_watch_unref(priv->watch);
|
||||
g_free(priv->imsi);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_sim_settings_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_SIM_SETTINGS_H
|
||||
#define RIL_SIM_SETTINGS_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ril_sim_settings_priv;
|
||||
|
||||
struct ril_sim_settings {
|
||||
GObject object;
|
||||
struct ril_sim_settings_priv *priv;
|
||||
const char *imsi;
|
||||
enum ofono_radio_access_mode techs;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
};
|
||||
|
||||
typedef void (*ril_sim_settings_cb_t)(struct ril_sim_settings *s, void *arg);
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs);
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *s,
|
||||
enum ofono_radio_access_mode mode);
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *s,
|
||||
ril_sim_settings_cb_t cb, void *arg);
|
||||
gulong ril_sim_settings_add_pref_mode_changed_handler(struct ril_sim_settings *s,
|
||||
ril_sim_settings_cb_t cb, void *arg);
|
||||
void ril_sim_settings_remove_handler(struct ril_sim_settings *s, gulong id);
|
||||
void ril_sim_settings_remove_handlers(struct ril_sim_settings *s, gulong *ids,
|
||||
int count);
|
||||
#define ril_sim_settings_remove_all_handlers(s,ids) \
|
||||
ril_sim_settings_remove_handlers(s, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_SIM_SETTINGS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,514 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#define RIL_SMS_ACK_RETRY_MS 1000
|
||||
#define RIL_SMS_ACK_RETRY_COUNT 10
|
||||
|
||||
#define SIM_EFSMS_FILEID 0x6F3C
|
||||
#define EFSMS_LENGTH 176
|
||||
|
||||
#define TYPE_LOCAL 129
|
||||
#define TYPE_INTERNATIONAL 145
|
||||
|
||||
static unsigned char sim_path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
|
||||
enum ril_sms_events {
|
||||
SMS_EVENT_NEW_SMS,
|
||||
SMS_EVENT_NEW_STATUS_REPORT,
|
||||
SMS_EVENT_NEW_SMS_ON_SIM,
|
||||
SMS_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sms {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_modem *modem;
|
||||
struct ofono_sms *sms;
|
||||
struct ofono_sim_context *sim_context;
|
||||
gulong event_id[SMS_EVENT_COUNT];
|
||||
guint timer_id;
|
||||
};
|
||||
|
||||
struct ril_sms_cbd {
|
||||
union _ofono_sms_cb {
|
||||
ofono_sms_sca_set_cb_t sca_set;
|
||||
ofono_sms_sca_query_cb_t sca_query;
|
||||
ofono_sms_submit_cb_t submit;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct ril_sms_on_sim_req {
|
||||
struct ril_sms *sd;
|
||||
int record;
|
||||
};
|
||||
|
||||
#define ril_sms_cbd_free g_free
|
||||
#define ril_sms_on_sim_req_free g_free
|
||||
|
||||
static inline struct ril_sms *ril_sms_get_data(struct ofono_sms *sms)
|
||||
{
|
||||
return ofono_sms_get_data(sms);
|
||||
}
|
||||
|
||||
struct ril_sms_cbd *ril_sms_cbd_new(struct ril_sms *sd, void *cb, void *data)
|
||||
{
|
||||
struct ril_sms_cbd *cbd = g_new0(struct ril_sms_cbd, 1);
|
||||
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
struct ril_sms_on_sim_req *ril_sms_on_sim_req_new(struct ril_sms *sd, int rec)
|
||||
{
|
||||
struct ril_sms_on_sim_req *cbd = g_new0(struct ril_sms_on_sim_req, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->record = rec;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sms_sca_set_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_sms_cbd *cbd = user_data;
|
||||
ofono_sms_sca_set_cb_t cb = cbd->cb.sca_set;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("csca setting failed");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sms_sca_set(struct ofono_sms *sms,
|
||||
const struct ofono_phone_number *sca,
|
||||
ofono_sms_sca_set_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 4];
|
||||
|
||||
if (sca->type == TYPE_LOCAL) {
|
||||
snprintf(number, sizeof(number), "\"%s\"", sca->number);
|
||||
} else {
|
||||
snprintf(number, sizeof(number), "\"+%s\"", sca->number);
|
||||
}
|
||||
|
||||
DBG("Setting sca: %s", number);
|
||||
grilio_request_append_utf8(req, number);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SET_SMSC_ADDRESS, ril_sms_sca_set_cb,
|
||||
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_sca_query_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms_cbd *cbd = user_data;
|
||||
ofono_sms_sca_query_cb_t cb = cbd->cb.sca_query;
|
||||
struct ofono_error error;
|
||||
GRilIoParser rilp;
|
||||
gchar *temp_buf;
|
||||
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("csca query failed");
|
||||
cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
temp_buf = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (temp_buf) {
|
||||
/* RIL gives address in quotes */
|
||||
gchar *number = strtok(temp_buf, "\"");
|
||||
struct ofono_phone_number sca;
|
||||
|
||||
strncpy(sca.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
|
||||
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
|
||||
if (sca.number[0] == '+') {
|
||||
number = number + 1;
|
||||
sca.type = TYPE_INTERNATIONAL;
|
||||
} else {
|
||||
sca.type = TYPE_LOCAL;
|
||||
}
|
||||
|
||||
DBG("csca_query_cb: %s, %d", sca.number, sca.type);
|
||||
cb(ril_error_ok(&error), &sca, cbd->data);
|
||||
g_free(temp_buf);
|
||||
} else {
|
||||
ofono_error("return value invalid");
|
||||
cb(ril_error_failure(&error), NULL, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sms_sca_query(struct ofono_sms *sms,
|
||||
ofono_sms_sca_query_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
|
||||
DBG("Sending csca_query");
|
||||
grilio_queue_send_request_full(sd->q, NULL,
|
||||
RIL_REQUEST_GET_SMSC_ADDRESS, ril_sms_sca_query_cb,
|
||||
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
|
||||
}
|
||||
|
||||
static void ril_sms_submit_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms_cbd *cbd = user_data;
|
||||
ofono_sms_submit_cb_t cb = cbd->cb.submit;
|
||||
struct ofono_error error;
|
||||
int mr = 0;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
int err = -1;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
/* TP-Message-Reference for GSM/
|
||||
* BearerData MessageId for CDMA
|
||||
*/
|
||||
grilio_parser_get_int32(&rilp, &mr);
|
||||
grilio_parser_skip_string(&rilp);
|
||||
|
||||
/* error: 3GPP 27.005, 3.2.5, -1 if unknown or not applicable */
|
||||
grilio_parser_get_int32(&rilp, &err);
|
||||
DBG("sms msg ref: %d, error: %d", mr, err);
|
||||
ril_error_init_ok(&error);
|
||||
} else if (status == RIL_E_GENERIC_FAILURE) {
|
||||
ofono_info("not allowed by MO SMS control, do not retry");
|
||||
error.type = OFONO_ERROR_TYPE_CMS;
|
||||
error.error = 500;
|
||||
} else {
|
||||
ofono_error("sms sending failed, retry");
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
cb(&error, mr, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
int pdu_len, int tpdu_len, int mms,
|
||||
ofono_sms_submit_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
int smsc_len;
|
||||
char *tpdu;
|
||||
|
||||
DBG("pdu_len: %d, tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
|
||||
|
||||
grilio_request_append_int32(req, 2); /* Number of strings */
|
||||
|
||||
/* SMSC address:
|
||||
*
|
||||
* smsc_len == 1, then zero-length SMSC was spec'd
|
||||
* RILD expects a NULL string in this case instead
|
||||
* of a zero-length string.
|
||||
*/
|
||||
smsc_len = pdu_len - tpdu_len;
|
||||
if (smsc_len > 1) {
|
||||
/* TODO: encode SMSC & write to parcel */
|
||||
DBG("SMSC address specified (smsc_len %d); NOT-IMPLEMENTED",
|
||||
smsc_len);
|
||||
}
|
||||
|
||||
grilio_request_append_utf8(req, NULL); /* default SMSC address */
|
||||
|
||||
/* TPDU:
|
||||
*
|
||||
* 'pdu' is a raw hexadecimal string
|
||||
* ril_encode_hex() turns it into an ASCII/hex buffer (subset of utf8)
|
||||
* grilio_request_append_utf8() encodes utf8 -> utf16
|
||||
*/
|
||||
tpdu = ril_encode_hex(pdu + smsc_len, tpdu_len);
|
||||
grilio_request_append_utf8(req, tpdu);
|
||||
|
||||
DBG("%s", tpdu);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
mms ? RIL_REQUEST_SEND_SMS_EXPECT_MORE : RIL_REQUEST_SEND_SMS,
|
||||
ril_sms_submit_cb, ril_sms_cbd_free,
|
||||
ril_sms_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
g_free(tpdu);
|
||||
}
|
||||
|
||||
static void ril_ack_delivery_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
if (status != RIL_E_SUCCESS) {
|
||||
ofono_error("SMS acknowledgement failed: "
|
||||
"Further SMS reception is not guaranteed");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_ack_delivery(struct ril_sms *sd, gboolean error)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(12);
|
||||
const int code = (error ? 0 : 0xff);
|
||||
|
||||
DBG("(%d,%d)", error, code);
|
||||
grilio_request_append_int32(req, 2); /* Array size*/
|
||||
grilio_request_append_int32(req, error); /* Success (1)/Failure (0) */
|
||||
grilio_request_append_int32(req, code); /* error code */
|
||||
|
||||
/* ACK the incoming NEW_SMS */
|
||||
grilio_request_set_retry(req, RIL_SMS_ACK_RETRY_MS,
|
||||
RIL_SMS_ACK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SMS_ACKNOWLEDGE, ril_ack_delivery_cb, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_notify(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms *sd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *ril_pdu;
|
||||
int ril_pdu_len;
|
||||
unsigned int smsc_len;
|
||||
guint ril_buf_len;
|
||||
guchar *ril_data;
|
||||
|
||||
ril_pdu = NULL;
|
||||
ril_data = NULL;
|
||||
|
||||
DBG("event: %d; data_len: %d", ril_event, len);
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
ril_pdu = grilio_parser_get_utf8(&rilp);
|
||||
if (ril_pdu == NULL)
|
||||
goto error;
|
||||
|
||||
ril_pdu_len = strlen(ril_pdu);
|
||||
|
||||
DBG("ril_pdu_len is %d", ril_pdu_len);
|
||||
ril_data = ril_decode_hex(ril_pdu, ril_pdu_len, &ril_buf_len);
|
||||
if (ril_data == NULL)
|
||||
goto error;
|
||||
|
||||
/* The first octect in the pdu contains the SMSC address length
|
||||
* which is the X following octects it reads. We add 1 octet to
|
||||
* the read length to take into account this read octet in order
|
||||
* to calculate the proper tpdu length.
|
||||
*/
|
||||
smsc_len = ril_data[0] + 1;
|
||||
ofono_info("sms received, smsc_len is %d", smsc_len);
|
||||
DBG("(%s)", ril_pdu);
|
||||
|
||||
if (ril_buf_len >= smsc_len) {
|
||||
if (ril_event == RIL_UNSOL_RESPONSE_NEW_SMS) {
|
||||
/* Last parameter is tpdu_len (substract SMSC length) */
|
||||
ofono_sms_deliver_notify(sd->sms, ril_data, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
} else {
|
||||
/* RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT */
|
||||
ofono_sms_status_notify(sd->sms, ril_data, ril_buf_len,
|
||||
ril_buf_len - smsc_len);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(ril_pdu);
|
||||
g_free(ril_data);
|
||||
ril_ack_delivery(sd, TRUE);
|
||||
return;
|
||||
|
||||
error:
|
||||
g_free(ril_pdu);
|
||||
g_free(ril_data);
|
||||
ril_ack_delivery(sd, FALSE);
|
||||
ofono_error("Unable to parse NEW_SMS notification");
|
||||
}
|
||||
|
||||
static void ril_new_sms_on_sim_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
DBG("%d", status);
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ofono_info("sms deleted from sim");
|
||||
} else {
|
||||
ofono_error("deleting sms from sim failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_request_delete_sms_om_sim(struct ril_sms *sd, int record)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG("Deleting record: %d", record);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Array length */
|
||||
grilio_request_append_int32(req, record);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_DELETE_SMS_ON_SIM,
|
||||
ril_new_sms_on_sim_cb, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_on_sim_cb(int ok, int total_length, int record,
|
||||
const unsigned char *sdata, int length, void *userdata)
|
||||
{
|
||||
struct ril_sms_on_sim_req *cbd = userdata;
|
||||
struct ril_sms *sd = cbd->sd;
|
||||
|
||||
/*
|
||||
* It seems when reading EFsms RIL returns the whole record including
|
||||
* the first status byte therefore we ignore that as we are only
|
||||
* interested of the following pdu
|
||||
*/
|
||||
/* The first octect in the pdu contains the SMSC address length
|
||||
* which is the X following octects it reads. We add 1 octet to
|
||||
* the read length to take into account this read octet in order
|
||||
* to calculate the proper tpdu length.
|
||||
*/
|
||||
if (ok) {
|
||||
unsigned int smsc_len = sdata[1] + 1;
|
||||
ofono_sms_deliver_notify(sd->sms, sdata + 1, length - 1,
|
||||
length - smsc_len - 1);
|
||||
ril_request_delete_sms_om_sim(sd, cbd->record);
|
||||
} else {
|
||||
ofono_error("cannot read sms from sim");
|
||||
}
|
||||
|
||||
ril_sms_on_sim_req_free(cbd);
|
||||
}
|
||||
|
||||
static void ril_sms_on_sim(GRilIoChannel *io, guint ril_event,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sms *sd = user_data;
|
||||
struct ofono_sim *sim = ril_modem_ofono_sim(sd->modem);
|
||||
int data_len = 0, rec = 0;
|
||||
GRilIoParser rilp;
|
||||
|
||||
ofono_info("new sms on sim");
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (sim &&
|
||||
grilio_parser_get_int32(&rilp, &data_len) && data_len > 0 &&
|
||||
grilio_parser_get_int32(&rilp, &rec)) {
|
||||
DBG("rec %d", rec);
|
||||
if (sd->sim_context) {
|
||||
ofono_sim_read_record(sd->sim_context,
|
||||
SIM_EFSMS_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
rec, EFSMS_LENGTH,
|
||||
sim_path, sizeof(sim_path),
|
||||
ril_sms_on_sim_cb,
|
||||
ril_sms_on_sim_req_new(sd,rec));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sms_register(gpointer user_data)
|
||||
{
|
||||
struct ril_sms *sd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(sd->timer_id);
|
||||
sd->timer_id = 0;
|
||||
ofono_sms_register(sd->sms);
|
||||
|
||||
/* Register event handlers */
|
||||
sd->event_id[SMS_EVENT_NEW_SMS] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_notify,
|
||||
RIL_UNSOL_RESPONSE_NEW_SMS, sd);
|
||||
sd->event_id[SMS_EVENT_NEW_STATUS_REPORT] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_notify,
|
||||
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, sd);
|
||||
sd->event_id[SMS_EVENT_NEW_SMS_ON_SIM] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_on_sim,
|
||||
RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, sd);
|
||||
|
||||
/* Single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ofono_sim *sim = ril_modem_ofono_sim(modem);
|
||||
struct ril_sms *sd = g_new0(struct ril_sms, 1);
|
||||
|
||||
sd->modem = modem;
|
||||
sd->sms = sms;
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->sim_context = ofono_sim_context_create(sim);
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
sd->timer_id = g_idle_add(ril_sms_register, sd);
|
||||
ofono_sms_set_data(sms, sd);
|
||||
|
||||
GASSERT(sd->sim_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_sms_remove(struct ofono_sms *sms)
|
||||
{
|
||||
unsigned int i;
|
||||
struct ril_sms *sd = ril_sms_get_data(sms);
|
||||
|
||||
DBG("");
|
||||
ofono_sms_set_data(sms, NULL);
|
||||
|
||||
if (sd->sim_context) {
|
||||
ofono_sim_context_free(sd->sim_context);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
|
||||
grilio_channel_remove_handler(sd->io, sd->event_id[i]);
|
||||
|
||||
}
|
||||
|
||||
if (sd->timer_id > 0) {
|
||||
g_source_remove(sd->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_unref(sd->io);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_sms_driver ril_sms_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_sms_probe,
|
||||
.remove = ril_sms_remove,
|
||||
.sca_query = ril_sms_sca_query,
|
||||
.sca_set = ril_sms_sca_set,
|
||||
.submit = ril_sms_submit,
|
||||
.bearer_query = NULL, /* FIXME: needs investigation. */
|
||||
.bearer_set = NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,305 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#ifndef UI_LANG
|
||||
# define UI_LANG "/var/lib/environment/nemo/locale.conf"
|
||||
#endif
|
||||
|
||||
enum ril_stk_events {
|
||||
STK_EVENT_PROACTIVE_COMMAND,
|
||||
STK_EVENT_SESSION_END,
|
||||
STK_EVENT_NOTIFY,
|
||||
STK_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_stk {
|
||||
struct ofono_stk *stk;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gulong event_id[STK_EVENT_COUNT];
|
||||
};
|
||||
|
||||
struct ril_stk_cbd {
|
||||
union _ofono_stk_cb {
|
||||
ofono_stk_envelope_cb_t envelope;
|
||||
ofono_stk_generic_cb_t generic;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_stk_cbd_free g_free
|
||||
|
||||
static inline struct ril_stk *ril_stk_get_data(struct ofono_stk *stk)
|
||||
{
|
||||
return ofono_stk_get_data(stk);
|
||||
}
|
||||
|
||||
struct ril_stk_cbd *ril_stk_cbd_new(void *cb, void *data)
|
||||
{
|
||||
struct ril_stk_cbd *cbd = g_new0(struct ril_stk_cbd, 1);
|
||||
|
||||
cbd->cb.ptr = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_stk_envelope_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_stk_cbd *cbd = user_data;
|
||||
ofono_stk_envelope_cb_t cb = cbd->cb.envelope;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG("%u bytes(s)", len);
|
||||
cb(ril_error_ok(&error), NULL, 0, cbd->data);
|
||||
} else {
|
||||
DBG("Envelope reply failure: %s", ril_error_to_string(status));
|
||||
cb(ril_error_failure(&error), NULL, 0, cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_envelope(struct ofono_stk *stk, int length,
|
||||
const unsigned char *cmd, ofono_stk_envelope_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char *hex_envelope = ril_encode_hex(cmd, length);
|
||||
|
||||
DBG("%s", hex_envelope);
|
||||
grilio_request_append_utf8(req, hex_envelope);
|
||||
g_free(hex_envelope);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND,
|
||||
ril_stk_envelope_cb, ril_stk_cbd_free,
|
||||
ril_stk_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_stk_terminal_response_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_stk_cbd *cbd = user_data;
|
||||
ofono_stk_generic_cb_t cb = cbd->cb.generic;
|
||||
|
||||
DBG("");
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
} else {
|
||||
ofono_error("Error in sending terminal response");
|
||||
cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_terminal_response(struct ofono_stk *stk, int length,
|
||||
const unsigned char *resp,
|
||||
ofono_stk_generic_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char *hex_tr = ril_encode_hex(resp, length);
|
||||
|
||||
DBG("rilmodem terminal response: %s", hex_tr);
|
||||
grilio_request_append_utf8(req, hex_tr);
|
||||
g_free(hex_tr);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE,
|
||||
ril_stk_terminal_response_cb,
|
||||
ril_stk_cbd_free, ril_stk_cbd_new(cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_stk_user_confirmation(struct ofono_stk *stk,
|
||||
ofono_bool_t confirm)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
DBG("%d", confirm);
|
||||
grilio_request_append_int32(req, 1); /* size of array */
|
||||
grilio_request_append_int32(req, confirm); /* yes/no */
|
||||
|
||||
grilio_queue_send_request(sd->q, req,
|
||||
RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_stk_pcmd_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint data_len, void *user_data)
|
||||
{
|
||||
struct ril_stk *sd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *pcmd;
|
||||
void *pdu;
|
||||
guint len;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_STK_PROACTIVE_COMMAND);
|
||||
grilio_parser_init(&rilp, data, data_len);
|
||||
pcmd = grilio_parser_get_utf8(&rilp);
|
||||
pdu = ril_decode_hex(pcmd, -1, &len);
|
||||
if (pdu) {
|
||||
DBG("pcmd: %s", pcmd);
|
||||
ofono_stk_proactive_command_notify(sd->stk, len, pdu);
|
||||
g_free(pdu);
|
||||
} else {
|
||||
ofono_warn("Failed to parse STK command %s", pcmd);
|
||||
}
|
||||
g_free(pcmd);
|
||||
}
|
||||
|
||||
static void ril_stk_event_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint data_len, void *user_data)
|
||||
{
|
||||
struct ril_stk *sd = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *pcmd;
|
||||
void *pdu;
|
||||
guint len;
|
||||
|
||||
/* Proactive command has been handled by the modem. */
|
||||
GASSERT(code == RIL_UNSOL_STK_EVENT_NOTIFY);
|
||||
grilio_parser_init(&rilp, data, data_len);
|
||||
pcmd = grilio_parser_get_utf8(&rilp);
|
||||
pdu = ril_decode_hex(pcmd, -1, &len);
|
||||
if (pdu) {
|
||||
DBG("pcmd: %s", pcmd);
|
||||
ofono_stk_proactive_command_handled_notify(sd->stk, len, pdu);
|
||||
g_free(pdu);
|
||||
} else {
|
||||
ofono_warn("Failed to parse STK event %s", pcmd);
|
||||
}
|
||||
g_free(pcmd);
|
||||
}
|
||||
|
||||
static void ril_stk_session_end_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_stk *sd = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(code == RIL_UNSOL_STK_SESSION_END);
|
||||
ofono_stk_proactive_session_end_notify(sd->stk);
|
||||
}
|
||||
|
||||
static void ril_stk_agent_ready(struct ofono_stk *stk)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
|
||||
DBG("");
|
||||
if (!sd->event_id[STK_EVENT_PROACTIVE_COMMAND]) {
|
||||
DBG("Subscribing notifications");
|
||||
sd->event_id[STK_EVENT_PROACTIVE_COMMAND] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_stk_pcmd_notify,
|
||||
RIL_UNSOL_STK_PROACTIVE_COMMAND, sd);
|
||||
|
||||
GASSERT(!sd->event_id[STK_EVENT_SESSION_END]);
|
||||
sd->event_id[STK_EVENT_SESSION_END] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_stk_session_end_notify,
|
||||
RIL_UNSOL_STK_SESSION_END, sd);
|
||||
|
||||
GASSERT(!sd->event_id[STK_EVENT_NOTIFY]);
|
||||
sd->event_id[STK_EVENT_NOTIFY] =
|
||||
grilio_channel_add_unsol_event_handler(sd->io,
|
||||
ril_stk_event_notify,
|
||||
RIL_UNSOL_STK_EVENT_NOTIFY, sd);
|
||||
|
||||
grilio_queue_send_request(sd->q, NULL,
|
||||
RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_stk_set_lang()
|
||||
{
|
||||
GError *error = NULL;
|
||||
GIOChannel* chan = g_io_channel_new_file(UI_LANG, "r", &error);
|
||||
if (chan) {
|
||||
GString* buf = g_string_new(NULL);
|
||||
gsize term;
|
||||
while (g_io_channel_read_line_string(chan, buf, &term, NULL) ==
|
||||
G_IO_STATUS_NORMAL) {
|
||||
char* lang;
|
||||
g_string_set_size(buf, term);
|
||||
lang = strstr(buf->str, "LANG=");
|
||||
if (lang) {
|
||||
setenv("LANG", lang + 5, TRUE);
|
||||
}
|
||||
}
|
||||
g_string_free(buf, TRUE);
|
||||
g_io_channel_unref(chan);
|
||||
} else {
|
||||
DBG("%s: %s", UI_LANG, error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_stk *sd = g_new0(struct ril_stk, 1);
|
||||
|
||||
DBG("");
|
||||
sd->stk = stk;
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
|
||||
ofono_stk_set_data(stk, sd);
|
||||
ofono_stk_register(stk);
|
||||
ril_stk_set_lang();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_stk_remove(struct ofono_stk *stk)
|
||||
{
|
||||
struct ril_stk *sd = ril_stk_get_data(stk);
|
||||
unsigned int i;
|
||||
|
||||
DBG("");
|
||||
ofono_stk_set_data(stk, NULL);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
|
||||
grilio_channel_remove_handler(sd->io, sd->event_id[i]);
|
||||
}
|
||||
|
||||
grilio_channel_unref(sd->io);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_unref(sd->q);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
const struct ofono_stk_driver ril_stk_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_stk_probe,
|
||||
.remove = ril_stk_remove,
|
||||
.envelope = ril_stk_envelope,
|
||||
.terminal_response = ril_stk_terminal_response,
|
||||
.user_confirmation = ril_stk_user_confirmation,
|
||||
.ready = ril_stk_agent_ready
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,373 +0,0 @@
|
||||
# This is a sample configuration file for Jolla ril driver
|
||||
#
|
||||
# This file is expected to be installed in /etc/ofono
|
||||
#
|
||||
# Configuration for each modem is defined in its own [ril_x] section,
|
||||
# common settings are in the [Settings] section, all other sections
|
||||
# are ignored.
|
||||
#
|
||||
# If any value from [ril_x] section (except "socket") is defined
|
||||
# in the [Settings] section, it becomes the default for all modems.
|
||||
# Default values can still be redefined at [ril_x] level.
|
||||
#
|
||||
|
||||
[Settings]
|
||||
|
||||
# This option stops RIL plugin from creating any RIL modems.
|
||||
# If it's set to true, all [ril_x] sections are ignored even
|
||||
# if they are present, and no default configurtation is created.
|
||||
#
|
||||
# Default false
|
||||
#
|
||||
#EmptyConfig=false
|
||||
|
||||
# User and group for the ofono process. RIL clients are typically
|
||||
# expected to run under radio:radio.
|
||||
#
|
||||
# Default radio:radio
|
||||
#
|
||||
#Identity=radio:radio
|
||||
|
||||
# If the phone has more than one SIM slot, the 3G/LTE module may be
|
||||
# shared by all modems, meaning that only one of the slots can use
|
||||
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
|
||||
# currently using 3G/LTE has to drop to GSM, release 3G/LTE module
|
||||
# and only then 3G/LTE can be used by the other modem. This setting
|
||||
# allows to disable this behaviour (say, if your phone has independent
|
||||
# 3G/LTE modules for each slot or you don't need 4G for both slots).
|
||||
# Obviously, it only has any effect if you have more than one SIM.
|
||||
#
|
||||
# Defaults to true (switch the current data modem to 2G when changing
|
||||
# the data modems)
|
||||
#
|
||||
#3GLTEHandover=true
|
||||
|
||||
# If this option is on, preferred technology is set to GSM for non-data
|
||||
# slots.
|
||||
#
|
||||
# Default true (for historical reasons)
|
||||
#
|
||||
#ForceGsmForNonDataSlots=true
|
||||
|
||||
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# It's involved in 3G/LTE handover between the modems, meaning that it only
|
||||
# makes sense if you have more than one slot.
|
||||
#
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default auto (enable for RIL version >= 11)
|
||||
#
|
||||
#SetRadioCapability=auto
|
||||
|
||||
[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.
|
||||
#
|
||||
# Default zero (no timeout)
|
||||
#
|
||||
#timeout=0
|
||||
|
||||
# Comma-separated list of radio technologies supported by the modem.
|
||||
# Valid technologies are "gsm", "umts" and "lte". The special value
|
||||
# "all" means that all technologies are supported.
|
||||
#
|
||||
# Default all
|
||||
#
|
||||
#technologies=all
|
||||
|
||||
# This one is deprecated, use the technologies entry instead (above).
|
||||
#
|
||||
#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 true (select SET_UICC_SUBSCRIPTION based on the RIL version)
|
||||
#
|
||||
#uiccWorkaround=true
|
||||
|
||||
# Points to the file containing comma-separated ECC (Emergency List Codes)
|
||||
# list, e.g. 911,112,*911,#911. The file is tracked by ofono and when its
|
||||
# contents changes, it's reflected in the EmergencyNumbers property of
|
||||
# org.ofono.VoiceCallManager.
|
||||
#
|
||||
# If necessary, the contents of the file can be synchronized with the
|
||||
# Android system property by adding something like this to /init.rc:
|
||||
#
|
||||
# on property:ril.ecclist=*
|
||||
# write /var/lib/ofono/ril.ecclist ${ril.ecclist}
|
||||
# chmod 0644 /var/lib/ofono/ril.ecclist
|
||||
#
|
||||
#ecclistFile=/var/lib/ofono/ril.ecclist
|
||||
|
||||
# RIL_REQUEST_ALLOW_DATA may or may not be supported by your RIL.
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default auto (enable for RIL version >= 11)
|
||||
#
|
||||
#allowDataReq=auto
|
||||
|
||||
# Since RIL interface doesn't provide the standard way of querying the
|
||||
# number of pin retries left, some RIL implementation (namely Qualcomm)
|
||||
# allow to query the retry count by sending the empty pin. If your RIL
|
||||
# actually does check the empty pin (and decrements the retry count)
|
||||
# then you should turn this feature off.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#emptyPinQuery=true
|
||||
|
||||
# Different RILs use different data call structures which don't necessarily
|
||||
# match the format specified in the data list header. The header may have
|
||||
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
|
||||
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
|
||||
# ofono assumes that the version from the list header matches the contents
|
||||
# but sometimes you have to explicitly tell ofono which one to use.
|
||||
# Possible values are 6, 9, 11 and auto.
|
||||
#
|
||||
# Default auto
|
||||
#
|
||||
#dataCallFormat=auto
|
||||
|
||||
# Data call may fail with status 65535 which according to ril.h means that
|
||||
# we need to retry silently. The maximum number of retries is limited by
|
||||
# this parameter. Usually, one retry is enough. The first retry occurs
|
||||
# immediately, the subsequent ones after dataCallRetryDelay (see below)
|
||||
#
|
||||
# Default 4
|
||||
#
|
||||
#dataCallRetryLimit=4
|
||||
|
||||
# Delay between data call retries, in milliseconds. Note that the first
|
||||
# retry occurs immediately after the first failure, the delays are only
|
||||
# applied if the first retry fails too.
|
||||
#
|
||||
# Default 200 ms
|
||||
#
|
||||
#dataCallRetryDelay=200
|
||||
|
||||
# Additional local and remote hangup reasons. Remote reasons are checked
|
||||
# first. Normally, RIL plugin figures it out automatically. You would only
|
||||
# need to define these if your RIL does something unusual.
|
||||
#
|
||||
# No default
|
||||
#
|
||||
#remoteHangupReasons=20
|
||||
#localHangupReasons=23
|
||||
|
||||
# Voice call support. Some devices like USB modems and tablets don't support
|
||||
# voice calls. By default, voice calls are enabled and this option allows you
|
||||
# to disable voice call handling.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableVoicecall=true
|
||||
|
||||
# Support for Cell Broadcast System (CBS). By default, its enabled but if
|
||||
# your rild and/or modem is not happy about it, you can turn it off.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableCellBroadcast=true
|
||||
|
||||
# Support for Sim Toolkit (STK). By default, its enabled but if your rild
|
||||
# and/or modem is not happy about it, you can turn it off.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableSimToolkit=true
|
||||
|
||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||
# show up before this timeout expires, will be dropped (ignored).
|
||||
#
|
||||
# In some fairly rare cases it makes sense to shorten this timeout for
|
||||
# optional modems (which may or may not be available), to speed up the
|
||||
# boot up process.
|
||||
#
|
||||
# Default 20000 (20 seconds)
|
||||
#
|
||||
#startTimeout=20000
|
||||
|
||||
# This allows to use deprecated RIL_REQUEST_GET_IMEI instead of
|
||||
# RIL_REQUEST_DEVICE_IDENTITY to query IMEI from the modem. Some
|
||||
# RILs (e.g. MTK) still don't understand RIL_REQUEST_DEVICE_IDENTITY.
|
||||
#
|
||||
# Default false (use RIL_REQUEST_DEVICE_IDENTITY)
|
||||
#
|
||||
#legacyImeiQuery=false
|
||||
|
||||
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
|
||||
# This option allows to set a custom LTE mode.
|
||||
#
|
||||
# Default 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
|
||||
#
|
||||
#lteNetworkMode=9
|
||||
|
||||
# UMTS network mode.
|
||||
#
|
||||
# Default 3 (PREF_NET_TYPE_GSM_WCDMA_AUTO)
|
||||
#
|
||||
#umtsNetworkMode=3
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
|
||||
#
|
||||
# Default 20000 (20 seconds)
|
||||
#
|
||||
#networkModeTimeout=20000
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC and
|
||||
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, in milliseconds.
|
||||
#
|
||||
# Default 100000 (100 seconds)
|
||||
#
|
||||
#networkSelectionTimeout=100000
|
||||
|
||||
# Comma-separated signal strength range, in dBm.
|
||||
#
|
||||
# These values are used for translating dBm values returned by the modem in
|
||||
# LTE mode into signal strength percentage. If you are getting significantly
|
||||
# different signal strength readings in GSM and LTE modes, you may need to
|
||||
# tweak those.
|
||||
#
|
||||
# Default -100,-60
|
||||
#
|
||||
#signalStrengthRange=-100,-60
|
||||
|
||||
# Cycle radio power at startup.
|
||||
#
|
||||
# Default true (cycle the power)
|
||||
#
|
||||
#radioPowerCycle=true
|
||||
|
||||
# With some RILs it seems to be necessary to kick (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).
|
||||
#
|
||||
# On the other hand, with some RILs it's causing some trouble (like this
|
||||
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
|
||||
#
|
||||
# Default true (for historical reasons)
|
||||
#
|
||||
#confirmRadioPowerOn=true
|
||||
|
||||
# Normally we should be able to have two simultaneously active data
|
||||
# contexts - one for mobile data and one for MMS. Some devices however
|
||||
# require that mobile data is disconnected before we can send or receive
|
||||
# MMS. In other words, activation of the second data context fails.
|
||||
#
|
||||
# Default false (more than one context is supported)
|
||||
#
|
||||
#singleDataContext=false
|
||||
|
||||
# With some RILs, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS returns strange
|
||||
# operator names, i.e. numeric MCC+MNC values or the same name for all
|
||||
# operators (which is actually SPN fetched from the SIM). Such strange
|
||||
# names can be replaced with operator names from MBPI database, based
|
||||
# on the operator's MCC and MNC. That may not be 100% accurate, though.
|
||||
#
|
||||
# Default false (i.e. trust RIL to report the actual names)
|
||||
#
|
||||
#replaceStrangeOperatorNames=false
|
||||
|
||||
# Configures whether +0 is added to MCCMNC string passed to
|
||||
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs
|
||||
# require it, some MediaTek RILs don't like it.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#networkSelectionManual0=true
|
||||
|
||||
# Enables use of SET_DATA_PROFILE requests. Everything used to work without
|
||||
# profiles, that's why it's disabled by default.
|
||||
#
|
||||
# Default false
|
||||
#
|
||||
#useDataProfiles=false
|
||||
|
||||
# Configures MMS data profile ID. Must be non-zero.
|
||||
# This option is ignored if useDataProfiles is false.
|
||||
#
|
||||
# Default 2 (RIL_DATA_PROFILE_IMS)
|
||||
#
|
||||
#mmsDataProfileId=2
|
||||
|
||||
# Configures device state tracking (basically, power saving strategy).
|
||||
# Possible values are:
|
||||
#
|
||||
# ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE)
|
||||
# ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE)
|
||||
# ur = Use URC filter (RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER)
|
||||
# This may be useful on devices with RIL version >= 15 if auto
|
||||
# method fails
|
||||
# auto = Choose ss or ds based on the RIL version
|
||||
# none = Disable device state management
|
||||
#
|
||||
# In addition to specifying ss, ds or ur method, one can specify a
|
||||
# combination of methods, e.g. ds+ur
|
||||
#
|
||||
# Default auto
|
||||
#
|
||||
#deviceStateTracking=auto
|
||||
|
||||
# On some phones (such as Jolla C), even if the slot which has been
|
||||
# using LTE gets powered off, we still need to explicitely set its
|
||||
# preferred mode to GSM, to make LTE machinery available to the other slot.
|
||||
#
|
||||
# Default true (false for MTK RILs)
|
||||
#
|
||||
#forceGsmWhenRadioOff=true
|
||||
|
||||
# Configures a period between RIL_UNSOL_CELL_INFO_LIST events when the device
|
||||
# is awake. Possible values are:
|
||||
#
|
||||
# 0 = invoke RIL_UNSOL_CELL_INFO_LIST when any of the reported information
|
||||
# changes
|
||||
# 1..INT_MAX-1 (2147483646) = sets update period in milliseconds
|
||||
# negative value or INT_MAX = never issue a RIL_UNSOL_CELL_INFO_LIST
|
||||
#
|
||||
# On MediaTek devices the period of RIL_UNSOL_CELL_INFO_LIST events can't be
|
||||
# configured. The parameter RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE has
|
||||
# non-standard meaning:
|
||||
#
|
||||
# 0 = enable RIL_UNSOL_CELL_INFO_LIST
|
||||
# any other value = disable RIL_UNSOL_CELL_INFO_LIST
|
||||
#
|
||||
# Default 2000
|
||||
#
|
||||
#cellInfoIntervalShortMs=2000
|
||||
|
||||
# Configures period between RIL_UNSOL_CELL_INFO_LIST events when the device is
|
||||
# in a power saving mode. For possible values, look cellInfoIntervalShortMs.
|
||||
#
|
||||
# Default 30000
|
||||
#
|
||||
#cellInfoIntervalLongMs=30000
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_TYPES_H
|
||||
#define RIL_TYPES_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <grilio_types.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
struct ofono_watch;
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
#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_data_call;
|
||||
struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_vendor;
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Mobile data not required */
|
||||
RIL_DATA_ROLE_MMS, /* Data is needed at any speed */
|
||||
RIL_DATA_ROLE_INTERNET /* Data is needed at full speed */
|
||||
};
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
enum ofono_radio_access_mode techs;
|
||||
enum ril_pref_net_type lte_network_mode;
|
||||
enum ril_pref_net_type umts_network_mode;
|
||||
int network_mode_timeout;
|
||||
int network_selection_timeout;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean empty_pin_query;
|
||||
gboolean radio_power_cycle;
|
||||
gboolean confirm_radio_power_on;
|
||||
gboolean enable_voicecall;
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean network_selection_manual_0;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
guint mms_data_profile_id;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
};
|
||||
|
||||
/* Some values copied from ofono's internal common.h */
|
||||
|
||||
/* 27.007 Section 7.11 */
|
||||
enum bearer_class {
|
||||
BEARER_CLASS_VOICE = 1,
|
||||
BEARER_CLASS_DATA = 2,
|
||||
BEARER_CLASS_FAX = 4,
|
||||
BEARER_CLASS_DEFAULT = 7,
|
||||
BEARER_CLASS_SMS = 8,
|
||||
BEARER_CLASS_DATA_SYNC = 16,
|
||||
BEARER_CLASS_DATA_ASYNC = 32,
|
||||
BEARER_CLASS_SS_DEFAULT = 61,
|
||||
BEARER_CLASS_PACKET = 64,
|
||||
BEARER_CLASS_PAD = 128
|
||||
};
|
||||
|
||||
#endif /* RIL_TYPES_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/misc.h>
|
||||
|
||||
#define USSD_REQUEST_TIMEOUT_SEC (30)
|
||||
#define USSD_CANCEL_TIMEOUT_SEC (20)
|
||||
|
||||
struct ril_ussd {
|
||||
struct ofono_ussd *ussd;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
guint request_id;
|
||||
guint cancel_id;
|
||||
guint timer_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_ussd_cbd {
|
||||
struct ril_ussd *ud;
|
||||
ofono_ussd_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd)
|
||||
{
|
||||
return ofono_ussd_get_data(ussd);
|
||||
}
|
||||
|
||||
static struct ril_ussd_cbd *ril_ussd_cbd_new(struct ril_ussd *ud,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd_cbd *cbd = g_slice_new(struct ril_ussd_cbd);
|
||||
|
||||
cbd->ud = ud;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_ussd_cbd_free(void *cbd)
|
||||
{
|
||||
g_slice_free(struct ril_ussd_cbd, cbd);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
struct ril_ussd *ud = cbd->ud;
|
||||
|
||||
/* Always report sucessful completion, otherwise ofono may get
|
||||
* stuck in the USSD_STATE_ACTIVE state */
|
||||
GASSERT(ud->cancel_id);
|
||||
ud->cancel_id = 0;
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_response(GRilIoChannel* channel, int status,
|
||||
const void* data, guint len, void* user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
struct ril_ussd *ud = cbd->ud;
|
||||
|
||||
GASSERT(ud->request_id);
|
||||
ud->request_id = 0;
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
cbd->cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
enum ofono_sms_charset charset;
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
ofono_info("send ussd, len:%d", len);
|
||||
GASSERT(!ud->request_id);
|
||||
if (ud->request_id) {
|
||||
grilio_queue_cancel_request(ud->q, ud->request_id, FALSE);
|
||||
ud->request_id = 0;
|
||||
}
|
||||
|
||||
if (ofono_decode_cbs_dcs_charset(dcs, &charset) &&
|
||||
charset == OFONO_SMS_CHARSET_7BIT) {
|
||||
char unpacked[182];
|
||||
unsigned int written = ofono_unpack_7bit(pdu, len,
|
||||
OFONO_UNPACK_7BIT_USSD, unpacked, sizeof(unpacked)-1);
|
||||
|
||||
unpacked[written] = 0;
|
||||
if (written >= 1) {
|
||||
/*
|
||||
* When USSD was packed, additional CR
|
||||
* might have been added (according to
|
||||
* 23.038 6.1.2.3.1). So if the last
|
||||
* character is CR, it should be removed
|
||||
* here.
|
||||
*
|
||||
* Over 2 characters long USSD string must
|
||||
* end with # (checked in valid_ussd_string),
|
||||
* so it should be safe to remove extra CR.
|
||||
*/
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
int length = strlen(unpacked);
|
||||
|
||||
while (length > 2 && unpacked[length-1] == '\r') {
|
||||
unpacked[--length] = 0;
|
||||
}
|
||||
grilio_request_append_utf8_chars(req, (char*)
|
||||
unpacked, length);
|
||||
grilio_request_set_timeout(req,
|
||||
USSD_REQUEST_TIMEOUT_SEC * 1000);
|
||||
ud->request_id = grilio_queue_send_request_full(ud->q,
|
||||
req, RIL_REQUEST_SEND_USSD,
|
||||
ril_ussd_response,
|
||||
ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(ud, cb, data));
|
||||
grilio_request_unref(req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
GASSERT(!ud->cancel_id);
|
||||
grilio_queue_cancel_request(ud->q, ud->cancel_id, FALSE);
|
||||
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
|
||||
ud->cancel_id = grilio_queue_send_request_full(ud->q, req,
|
||||
RIL_REQUEST_CANCEL_USSD, ril_ussd_cancel_cb,
|
||||
ril_ussd_cbd_free, ril_ussd_cbd_new(ud, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_ussd_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_ussd *ud = user_data;
|
||||
GRilIoParser rilp;
|
||||
char *type;
|
||||
guint32 n = 0;
|
||||
|
||||
ofono_info("ussd received");
|
||||
|
||||
GASSERT(code == RIL_UNSOL_ON_USSD);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
grilio_parser_get_uint32(&rilp, &n);
|
||||
type = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
if (type) {
|
||||
int ussdtype = g_ascii_xdigit_value(*type);
|
||||
char *msg = (n > 1) ? grilio_parser_get_utf8(&rilp) : NULL;
|
||||
|
||||
if (msg) {
|
||||
const int msglen = strlen(msg);
|
||||
DBG("ussd length %d", msglen);
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
|
||||
(const unsigned char *)msg, msglen);
|
||||
/* msg is freed by core if dcs is 0xFF */
|
||||
} else {
|
||||
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
|
||||
}
|
||||
|
||||
g_free(type);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_ussd_register(gpointer user_data)
|
||||
{
|
||||
struct ril_ussd *ud = user_data;
|
||||
|
||||
DBG("");
|
||||
GASSERT(ud->timer_id);
|
||||
ud->timer_id = 0;
|
||||
ofono_ussd_register(ud->ussd);
|
||||
|
||||
/* Register for USSD events */
|
||||
ud->event_id = grilio_channel_add_unsol_event_handler(ud->io,
|
||||
ril_ussd_notify, RIL_UNSOL_ON_USSD, ud);
|
||||
|
||||
/* Single-shot */
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_ussd *ud = g_try_new0(struct ril_ussd, 1);
|
||||
|
||||
DBG("");
|
||||
ud->ussd = ussd;
|
||||
ud->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
ud->q = grilio_queue_new(ud->io);
|
||||
ud->timer_id = g_idle_add(ril_ussd_register, ud);
|
||||
ofono_ussd_set_data(ussd, ud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ril_ussd_remove(struct ofono_ussd *ussd)
|
||||
{
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
DBG("");
|
||||
ofono_ussd_set_data(ussd, NULL);
|
||||
|
||||
if (ud->timer_id > 0) {
|
||||
g_source_remove(ud->timer_id);
|
||||
}
|
||||
|
||||
grilio_channel_remove_handler(ud->io, ud->event_id);
|
||||
grilio_channel_unref(ud->io);
|
||||
grilio_queue_cancel_all(ud->q, FALSE);
|
||||
grilio_queue_unref(ud->q);
|
||||
g_free(ud);
|
||||
}
|
||||
|
||||
const struct ofono_ussd_driver ril_ussd_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_ussd_probe,
|
||||
.remove = ril_ussd_remove,
|
||||
.request = ril_ussd_request,
|
||||
.cancel = ril_ussd_cancel
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,512 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
#include <ofono/misc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define RIL_PROTO_IP_STR "IP"
|
||||
#define RIL_PROTO_IPV6_STR "IPV6"
|
||||
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
|
||||
|
||||
const char *ril_error_to_string(int error)
|
||||
{
|
||||
#define RIL_E_(name) case RIL_E_##name: return #name
|
||||
#define GRILIO_E_(name) case GRILIO_STATUS_##name: return "GRILIO_" #name
|
||||
static char unknown[12];
|
||||
switch (error) {
|
||||
case RIL_E_SUCCESS: return "OK";
|
||||
GRILIO_E_(TIMEOUT);
|
||||
GRILIO_E_(CANCELLED);
|
||||
RIL_E_(RADIO_NOT_AVAILABLE);
|
||||
RIL_E_(GENERIC_FAILURE);
|
||||
RIL_E_(PASSWORD_INCORRECT);
|
||||
RIL_E_(SIM_PIN2);
|
||||
RIL_E_(SIM_PUK2);
|
||||
RIL_E_(REQUEST_NOT_SUPPORTED);
|
||||
RIL_E_(CANCELLED);
|
||||
RIL_E_(OP_NOT_ALLOWED_DURING_VOICE_CALL);
|
||||
RIL_E_(OP_NOT_ALLOWED_BEFORE_REG_TO_NW);
|
||||
RIL_E_(SMS_SEND_FAIL_RETRY);
|
||||
RIL_E_(SIM_ABSENT);
|
||||
RIL_E_(SUBSCRIPTION_NOT_AVAILABLE);
|
||||
RIL_E_(MODE_NOT_SUPPORTED);
|
||||
RIL_E_(FDN_CHECK_FAILURE);
|
||||
RIL_E_(ILLEGAL_SIM_OR_ME);
|
||||
RIL_E_(MISSING_RESOURCE);
|
||||
RIL_E_(NO_SUCH_ELEMENT);
|
||||
RIL_E_(DIAL_MODIFIED_TO_USSD);
|
||||
RIL_E_(DIAL_MODIFIED_TO_SS);
|
||||
RIL_E_(DIAL_MODIFIED_TO_DIAL);
|
||||
RIL_E_(USSD_MODIFIED_TO_DIAL);
|
||||
RIL_E_(USSD_MODIFIED_TO_SS);
|
||||
RIL_E_(USSD_MODIFIED_TO_USSD);
|
||||
RIL_E_(SS_MODIFIED_TO_DIAL);
|
||||
RIL_E_(SS_MODIFIED_TO_USSD);
|
||||
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
|
||||
RIL_E_(SS_MODIFIED_TO_SS);
|
||||
RIL_E_(LCE_NOT_SUPPORTED);
|
||||
RIL_E_(NO_MEMORY);
|
||||
RIL_E_(INTERNAL_ERR);
|
||||
RIL_E_(SYSTEM_ERR);
|
||||
RIL_E_(MODEM_ERR);
|
||||
RIL_E_(INVALID_STATE);
|
||||
RIL_E_(NO_RESOURCES);
|
||||
RIL_E_(SIM_ERR);
|
||||
RIL_E_(INVALID_ARGUMENTS);
|
||||
RIL_E_(INVALID_SIM_STATE);
|
||||
RIL_E_(INVALID_MODEM_STATE);
|
||||
RIL_E_(INVALID_CALL_ID);
|
||||
RIL_E_(NO_SMS_TO_ACK);
|
||||
RIL_E_(NETWORK_ERR);
|
||||
RIL_E_(REQUEST_RATE_LIMITED);
|
||||
RIL_E_(SIM_BUSY);
|
||||
RIL_E_(SIM_FULL);
|
||||
RIL_E_(NETWORK_REJECT);
|
||||
RIL_E_(OPERATION_NOT_ALLOWED);
|
||||
RIL_E_(EMPTY_RECORD);
|
||||
RIL_E_(INVALID_SMS_FORMAT);
|
||||
RIL_E_(ENCODING_ERR);
|
||||
RIL_E_(INVALID_SMSC_ADDRESS);
|
||||
RIL_E_(NO_SUCH_ENTRY);
|
||||
RIL_E_(NETWORK_NOT_READY);
|
||||
RIL_E_(NOT_PROVISIONED);
|
||||
RIL_E_(NO_SUBSCRIPTION);
|
||||
RIL_E_(NO_NETWORK_FOUND);
|
||||
RIL_E_(DEVICE_IN_USE);
|
||||
RIL_E_(ABORTED);
|
||||
RIL_E_(INVALID_RESPONSE);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "%d", error);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_request_to_string(guint request)
|
||||
{
|
||||
#define RIL_REQUEST_(name) case RIL_REQUEST_##name: return #name
|
||||
static char unknown[24];
|
||||
switch (request) {
|
||||
RIL_REQUEST_(GET_SIM_STATUS);
|
||||
RIL_REQUEST_(ENTER_SIM_PIN);
|
||||
RIL_REQUEST_(ENTER_SIM_PUK);
|
||||
RIL_REQUEST_(ENTER_SIM_PIN2);
|
||||
RIL_REQUEST_(ENTER_SIM_PUK2);
|
||||
RIL_REQUEST_(CHANGE_SIM_PIN);
|
||||
RIL_REQUEST_(CHANGE_SIM_PIN2);
|
||||
RIL_REQUEST_(ENTER_NETWORK_DEPERSONALIZATION);
|
||||
RIL_REQUEST_(GET_CURRENT_CALLS);
|
||||
RIL_REQUEST_(DIAL);
|
||||
RIL_REQUEST_(GET_IMSI);
|
||||
RIL_REQUEST_(HANGUP);
|
||||
RIL_REQUEST_(HANGUP_WAITING_OR_BACKGROUND);
|
||||
RIL_REQUEST_(HANGUP_FOREGROUND_RESUME_BACKGROUND);
|
||||
RIL_REQUEST_(SWITCH_HOLDING_AND_ACTIVE);
|
||||
RIL_REQUEST_(CONFERENCE);
|
||||
RIL_REQUEST_(UDUB);
|
||||
RIL_REQUEST_(LAST_CALL_FAIL_CAUSE);
|
||||
RIL_REQUEST_(SIGNAL_STRENGTH);
|
||||
RIL_REQUEST_(VOICE_REGISTRATION_STATE);
|
||||
RIL_REQUEST_(DATA_REGISTRATION_STATE);
|
||||
RIL_REQUEST_(OPERATOR);
|
||||
RIL_REQUEST_(RADIO_POWER);
|
||||
RIL_REQUEST_(DTMF);
|
||||
RIL_REQUEST_(SEND_SMS);
|
||||
RIL_REQUEST_(SEND_SMS_EXPECT_MORE);
|
||||
RIL_REQUEST_(SETUP_DATA_CALL);
|
||||
RIL_REQUEST_(SIM_IO);
|
||||
RIL_REQUEST_(SEND_USSD);
|
||||
RIL_REQUEST_(CANCEL_USSD);
|
||||
RIL_REQUEST_(GET_CLIR);
|
||||
RIL_REQUEST_(SET_CLIR);
|
||||
RIL_REQUEST_(QUERY_CALL_FORWARD_STATUS);
|
||||
RIL_REQUEST_(SET_CALL_FORWARD);
|
||||
RIL_REQUEST_(QUERY_CALL_WAITING);
|
||||
RIL_REQUEST_(SET_CALL_WAITING);
|
||||
RIL_REQUEST_(SMS_ACKNOWLEDGE);
|
||||
RIL_REQUEST_(GET_IMEI);
|
||||
RIL_REQUEST_(GET_IMEISV);
|
||||
RIL_REQUEST_(ANSWER);
|
||||
RIL_REQUEST_(DEACTIVATE_DATA_CALL);
|
||||
RIL_REQUEST_(QUERY_FACILITY_LOCK);
|
||||
RIL_REQUEST_(SET_FACILITY_LOCK);
|
||||
RIL_REQUEST_(CHANGE_BARRING_PASSWORD);
|
||||
RIL_REQUEST_(QUERY_NETWORK_SELECTION_MODE);
|
||||
RIL_REQUEST_(SET_NETWORK_SELECTION_AUTOMATIC);
|
||||
RIL_REQUEST_(SET_NETWORK_SELECTION_MANUAL);
|
||||
RIL_REQUEST_(QUERY_AVAILABLE_NETWORKS);
|
||||
RIL_REQUEST_(DTMF_START);
|
||||
RIL_REQUEST_(DTMF_STOP);
|
||||
RIL_REQUEST_(BASEBAND_VERSION);
|
||||
RIL_REQUEST_(SEPARATE_CONNECTION);
|
||||
RIL_REQUEST_(SET_MUTE);
|
||||
RIL_REQUEST_(GET_MUTE);
|
||||
RIL_REQUEST_(QUERY_CLIP);
|
||||
RIL_REQUEST_(LAST_DATA_CALL_FAIL_CAUSE);
|
||||
RIL_REQUEST_(DATA_CALL_LIST);
|
||||
RIL_REQUEST_(RESET_RADIO);
|
||||
RIL_REQUEST_(OEM_HOOK_RAW);
|
||||
RIL_REQUEST_(OEM_HOOK_STRINGS);
|
||||
RIL_REQUEST_(SCREEN_STATE);
|
||||
RIL_REQUEST_(SET_SUPP_SVC_NOTIFICATION);
|
||||
RIL_REQUEST_(WRITE_SMS_TO_SIM);
|
||||
RIL_REQUEST_(DELETE_SMS_ON_SIM);
|
||||
RIL_REQUEST_(SET_BAND_MODE);
|
||||
RIL_REQUEST_(QUERY_AVAILABLE_BAND_MODE);
|
||||
RIL_REQUEST_(STK_GET_PROFILE);
|
||||
RIL_REQUEST_(STK_SET_PROFILE);
|
||||
RIL_REQUEST_(STK_SEND_ENVELOPE_COMMAND);
|
||||
RIL_REQUEST_(STK_SEND_TERMINAL_RESPONSE);
|
||||
RIL_REQUEST_(STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM);
|
||||
RIL_REQUEST_(EXPLICIT_CALL_TRANSFER);
|
||||
RIL_REQUEST_(SET_PREFERRED_NETWORK_TYPE);
|
||||
RIL_REQUEST_(GET_PREFERRED_NETWORK_TYPE);
|
||||
RIL_REQUEST_(GET_NEIGHBORING_CELL_IDS);
|
||||
RIL_REQUEST_(SET_LOCATION_UPDATES);
|
||||
RIL_REQUEST_(CDMA_SET_SUBSCRIPTION_SOURCE);
|
||||
RIL_REQUEST_(CDMA_SET_ROAMING_PREFERENCE);
|
||||
RIL_REQUEST_(CDMA_QUERY_ROAMING_PREFERENCE);
|
||||
RIL_REQUEST_(SET_TTY_MODE);
|
||||
RIL_REQUEST_(QUERY_TTY_MODE);
|
||||
RIL_REQUEST_(CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE);
|
||||
RIL_REQUEST_(CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE);
|
||||
RIL_REQUEST_(CDMA_FLASH);
|
||||
RIL_REQUEST_(CDMA_BURST_DTMF);
|
||||
RIL_REQUEST_(CDMA_VALIDATE_AND_WRITE_AKEY);
|
||||
RIL_REQUEST_(CDMA_SEND_SMS);
|
||||
RIL_REQUEST_(CDMA_SMS_ACKNOWLEDGE);
|
||||
RIL_REQUEST_(GSM_GET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(GSM_SET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(GSM_SMS_BROADCAST_ACTIVATION);
|
||||
RIL_REQUEST_(CDMA_GET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(CDMA_SET_BROADCAST_SMS_CONFIG);
|
||||
RIL_REQUEST_(CDMA_SMS_BROADCAST_ACTIVATION);
|
||||
RIL_REQUEST_(CDMA_SUBSCRIPTION);
|
||||
RIL_REQUEST_(CDMA_WRITE_SMS_TO_RUIM);
|
||||
RIL_REQUEST_(CDMA_DELETE_SMS_ON_RUIM);
|
||||
RIL_REQUEST_(DEVICE_IDENTITY);
|
||||
RIL_REQUEST_(EXIT_EMERGENCY_CALLBACK_MODE);
|
||||
RIL_REQUEST_(GET_SMSC_ADDRESS);
|
||||
RIL_REQUEST_(SET_SMSC_ADDRESS);
|
||||
RIL_REQUEST_(REPORT_SMS_MEMORY_STATUS);
|
||||
RIL_REQUEST_(REPORT_STK_SERVICE_IS_RUNNING);
|
||||
RIL_REQUEST_(CDMA_GET_SUBSCRIPTION_SOURCE);
|
||||
RIL_REQUEST_(ISIM_AUTHENTICATION);
|
||||
RIL_REQUEST_(ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU);
|
||||
RIL_REQUEST_(STK_SEND_ENVELOPE_WITH_STATUS);
|
||||
RIL_REQUEST_(VOICE_RADIO_TECH);
|
||||
RIL_REQUEST_(GET_CELL_INFO_LIST);
|
||||
RIL_REQUEST_(SET_UNSOL_CELL_INFO_LIST_RATE);
|
||||
RIL_REQUEST_(SET_INITIAL_ATTACH_APN);
|
||||
RIL_REQUEST_(IMS_REGISTRATION_STATE);
|
||||
RIL_REQUEST_(IMS_SEND_SMS);
|
||||
RIL_REQUEST_(SIM_TRANSMIT_APDU_BASIC);
|
||||
RIL_REQUEST_(SIM_OPEN_CHANNEL);
|
||||
RIL_REQUEST_(SIM_CLOSE_CHANNEL);
|
||||
RIL_REQUEST_(SIM_TRANSMIT_APDU_CHANNEL);
|
||||
RIL_REQUEST_(NV_READ_ITEM);
|
||||
RIL_REQUEST_(NV_WRITE_ITEM);
|
||||
RIL_REQUEST_(NV_WRITE_CDMA_PRL);
|
||||
RIL_REQUEST_(NV_RESET_CONFIG);
|
||||
RIL_REQUEST_(SET_UICC_SUBSCRIPTION);
|
||||
RIL_REQUEST_(ALLOW_DATA);
|
||||
RIL_REQUEST_(GET_HARDWARE_CONFIG);
|
||||
RIL_REQUEST_(SIM_AUTHENTICATION);
|
||||
RIL_REQUEST_(GET_DC_RT_INFO);
|
||||
RIL_REQUEST_(SET_DC_RT_INFO_RATE);
|
||||
RIL_REQUEST_(SET_DATA_PROFILE);
|
||||
RIL_REQUEST_(SHUTDOWN);
|
||||
RIL_REQUEST_(GET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(SET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(START_LCE);
|
||||
RIL_REQUEST_(STOP_LCE);
|
||||
RIL_REQUEST_(GET_ACTIVITY_INFO);
|
||||
RIL_REQUEST_(GET_CARRIER_RESTRICTIONS);
|
||||
RIL_REQUEST_(SEND_DEVICE_STATE);
|
||||
RIL_REQUEST_(SET_UNSOLICITED_RESPONSE_FILTER);
|
||||
RIL_REQUEST_(SET_SIM_CARD_POWER);
|
||||
RIL_REQUEST_(SET_CARRIER_INFO_IMSI_ENCRYPTION);
|
||||
RIL_REQUEST_(START_NETWORK_SCAN);
|
||||
RIL_REQUEST_(STOP_NETWORK_SCAN);
|
||||
RIL_REQUEST_(START_KEEPALIVE);
|
||||
RIL_REQUEST_(STOP_KEEPALIVE);
|
||||
case RIL_RESPONSE_ACKNOWLEDGEMENT:
|
||||
return "RESPONSE_ACK";
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_unsol_event_to_string(guint event)
|
||||
{
|
||||
#define RIL_UNSOL_(name) case RIL_UNSOL_##name: return #name
|
||||
static char unknown[24];
|
||||
switch (event) {
|
||||
RIL_UNSOL_(RESPONSE_RADIO_STATE_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_CALL_STATE_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_VOICE_NETWORK_STATE_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_NEW_SMS);
|
||||
RIL_UNSOL_(RESPONSE_NEW_SMS_STATUS_REPORT);
|
||||
RIL_UNSOL_(RESPONSE_NEW_SMS_ON_SIM);
|
||||
RIL_UNSOL_(ON_USSD);
|
||||
RIL_UNSOL_(ON_USSD_REQUEST);
|
||||
RIL_UNSOL_(NITZ_TIME_RECEIVED);
|
||||
RIL_UNSOL_(SIGNAL_STRENGTH);
|
||||
RIL_UNSOL_(DATA_CALL_LIST_CHANGED);
|
||||
RIL_UNSOL_(SUPP_SVC_NOTIFICATION);
|
||||
RIL_UNSOL_(STK_SESSION_END);
|
||||
RIL_UNSOL_(STK_PROACTIVE_COMMAND);
|
||||
RIL_UNSOL_(STK_EVENT_NOTIFY);
|
||||
RIL_UNSOL_(STK_CALL_SETUP);
|
||||
RIL_UNSOL_(SIM_SMS_STORAGE_FULL);
|
||||
RIL_UNSOL_(SIM_REFRESH);
|
||||
RIL_UNSOL_(CALL_RING);
|
||||
RIL_UNSOL_(RESPONSE_SIM_STATUS_CHANGED);
|
||||
RIL_UNSOL_(RESPONSE_CDMA_NEW_SMS);
|
||||
RIL_UNSOL_(RESPONSE_NEW_BROADCAST_SMS);
|
||||
RIL_UNSOL_(CDMA_RUIM_SMS_STORAGE_FULL);
|
||||
RIL_UNSOL_(RESTRICTED_STATE_CHANGED);
|
||||
RIL_UNSOL_(ENTER_EMERGENCY_CALLBACK_MODE);
|
||||
RIL_UNSOL_(CDMA_CALL_WAITING);
|
||||
RIL_UNSOL_(CDMA_OTA_PROVISION_STATUS);
|
||||
RIL_UNSOL_(CDMA_INFO_REC);
|
||||
RIL_UNSOL_(OEM_HOOK_RAW);
|
||||
RIL_UNSOL_(RINGBACK_TONE);
|
||||
RIL_UNSOL_(RESEND_INCALL_MUTE);
|
||||
RIL_UNSOL_(CDMA_SUBSCRIPTION_SOURCE_CHANGED);
|
||||
RIL_UNSOL_(CDMA_PRL_CHANGED);
|
||||
RIL_UNSOL_(EXIT_EMERGENCY_CALLBACK_MODE);
|
||||
RIL_UNSOL_(RIL_CONNECTED);
|
||||
RIL_UNSOL_(VOICE_RADIO_TECH_CHANGED);
|
||||
RIL_UNSOL_(CELL_INFO_LIST);
|
||||
RIL_UNSOL_(RESPONSE_IMS_NETWORK_STATE_CHANGED);
|
||||
RIL_UNSOL_(UICC_SUBSCRIPTION_STATUS_CHANGED);
|
||||
RIL_UNSOL_(SRVCC_STATE_NOTIFY);
|
||||
RIL_UNSOL_(HARDWARE_CONFIG_CHANGED);
|
||||
RIL_UNSOL_(DC_RT_INFO_CHANGED);
|
||||
RIL_UNSOL_(RADIO_CAPABILITY);
|
||||
RIL_UNSOL_(ON_SS);
|
||||
RIL_UNSOL_(STK_CC_ALPHA_NOTIFY);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_UNSOL_%d", event);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_radio_state_to_string(int radio_state)
|
||||
{
|
||||
#define RADIO_STATE_(name) case RADIO_STATE_##name: return #name
|
||||
static char unknown[16];
|
||||
switch (radio_state) {
|
||||
RADIO_STATE_(OFF);
|
||||
RADIO_STATE_(UNAVAILABLE);
|
||||
RADIO_STATE_(SIM_NOT_READY);
|
||||
RADIO_STATE_(SIM_LOCKED_OR_ABSENT);
|
||||
RADIO_STATE_(SIM_READY);
|
||||
RADIO_STATE_(RUIM_NOT_READY);
|
||||
RADIO_STATE_(RUIM_READY);
|
||||
RADIO_STATE_(RUIM_LOCKED_OR_ABSENT);
|
||||
RADIO_STATE_(NV_NOT_READY);
|
||||
RADIO_STATE_(NV_READY);
|
||||
RADIO_STATE_(ON);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "%d (?)", radio_state);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case OFONO_GPRS_PROTO_IPV6:
|
||||
return RIL_PROTO_IPV6_STR;
|
||||
case OFONO_GPRS_PROTO_IPV4V6:
|
||||
return RIL_PROTO_IPV4V6_STR;
|
||||
case OFONO_GPRS_PROTO_IP:
|
||||
return RIL_PROTO_IP_STR;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ril_protocol_to_ofono(const gchar *str)
|
||||
{
|
||||
if (str) {
|
||||
if (!strcmp(str, RIL_PROTO_IPV6_STR)) {
|
||||
return OFONO_GPRS_PROTO_IPV6;
|
||||
} else if (!strcmp(str, RIL_PROTO_IPV4V6_STR)) {
|
||||
return OFONO_GPRS_PROTO_IPV4V6;
|
||||
} else if (!strcmp(str, RIL_PROTO_IP_STR)) {
|
||||
return OFONO_GPRS_PROTO_IP;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth)
|
||||
{
|
||||
switch (auth) {
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
return RIL_AUTH_NONE;
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
return RIL_AUTH_CHAP;
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
return RIL_AUTH_PAP;
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
/* Use default */
|
||||
break;
|
||||
}
|
||||
/* Default */
|
||||
return RIL_AUTH_BOTH;
|
||||
}
|
||||
|
||||
enum ofono_access_technology ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
int tech = -1;
|
||||
enum ofono_access_technology access_tech =
|
||||
OFONO_ACCESS_TECHNOLOGY_NONE;
|
||||
|
||||
if (gutil_parse_int(stech, 0, &tech)) {
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_GSM;
|
||||
break;
|
||||
case RADIO_TECH_EDGE:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_GSM_EGPRS;
|
||||
break;
|
||||
case RADIO_TECH_UMTS:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN;
|
||||
break;
|
||||
case RADIO_TECH_HSDPA:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA;
|
||||
break;
|
||||
case RADIO_TECH_HSUPA:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_HSPA:
|
||||
case RADIO_TECH_HSPAP:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_LTE:
|
||||
case RADIO_TECH_LTE_CA:
|
||||
access_tech = OFONO_ACCESS_TECHNOLOGY_EUTRAN;
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown RIL tech %s", stech);
|
||||
/* no break */
|
||||
case RADIO_TECH_IWLAN:
|
||||
case RADIO_TECH_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (ril_tech) {
|
||||
*ril_tech = tech;
|
||||
}
|
||||
return access_tech;
|
||||
}
|
||||
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
{
|
||||
if (str) {
|
||||
int i;
|
||||
const char *ptr = str;
|
||||
|
||||
/* Three digit country code */
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mcc[i] = *ptr++;
|
||||
}
|
||||
op->mcc[i] = 0;
|
||||
|
||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||
/* Usually 2 but sometimes 3 digit network code */
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
op->mnc[i] = 0;
|
||||
|
||||
if (i > 0) {
|
||||
|
||||
/*
|
||||
* Sometimes MCC/MNC are followed by + and
|
||||
* what looks like the technology code. This
|
||||
* is of course completely undocumented.
|
||||
*/
|
||||
if (*ptr == '+') {
|
||||
int tech = ril_parse_tech(ptr+1, NULL);
|
||||
if (tech >= 0) {
|
||||
op->tech = tech;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* ril_encode_hex(const void *in, guint size)
|
||||
{
|
||||
char *out = g_new(char, size * 2 + 1);
|
||||
|
||||
ofono_encode_hex(in, size, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void *ril_decode_hex(const char *hex, int len, guint *out_size)
|
||||
{
|
||||
void *out = NULL;
|
||||
guint size = 0;
|
||||
|
||||
if (hex) {
|
||||
if (len < 0) {
|
||||
len = (int) strlen(hex);
|
||||
}
|
||||
if (len > 0 && !(len & 1)) {
|
||||
size = len/2;
|
||||
out = g_malloc(size);
|
||||
if (!gutil_hex2bin(hex, len, out)) {
|
||||
g_free(out);
|
||||
out = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (out_size) {
|
||||
*out_size = size;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_UTIL_H
|
||||
#define RIL_UTIL_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/gprs-context.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
const char *ril_error_to_string(int error);
|
||||
const char *ril_request_to_string(guint request);
|
||||
const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto);
|
||||
int ril_protocol_to_ofono(const char *str);
|
||||
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth);
|
||||
enum ofono_access_technology ril_parse_tech(const char *stech, int *ril_tech);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
|
||||
#define ril_error_init_ok(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||
#define ril_error_init_failure(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_FAILURE)
|
||||
#define ril_error_init_sim_error(err,sw1,sw2) \
|
||||
((err)->error = ((sw1) << 8)|(sw2), (err)->type = OFONO_ERROR_TYPE_SIM)
|
||||
|
||||
#define ril_error_ok(err) (ril_error_init_ok(err), err)
|
||||
#define ril_error_failure(err) (ril_error_init_failure(err), err)
|
||||
#define ril_error_sim(err,sw1,sw2) (ril_error_init_sim_error(err,sw1,sw2), err)
|
||||
|
||||
char *ril_encode_hex(const void *in, guint size);
|
||||
void *ril_decode_hex(const char *hex, int len, guint *out_size);
|
||||
|
||||
#endif /* RIL_UTIL_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_vendor.h"
|
||||
#include "ril_vendor_impl.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(RilVendor, ril_vendor, G_TYPE_OBJECT)
|
||||
|
||||
/* Vendor driver descriptors are in the "__vendor" section */
|
||||
extern const struct ril_vendor_driver __start___vendor[];
|
||||
extern const struct ril_vendor_driver __stop___vendor[];
|
||||
|
||||
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name)
|
||||
{
|
||||
if (name) {
|
||||
const struct ril_vendor_driver *d;
|
||||
|
||||
for (d = __start___vendor; d < __stop___vendor; d++) {
|
||||
if (!strcasecmp(d->name, name)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RilVendor *ril_vendor_create(const struct ril_vendor_driver *driver,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
return (driver && driver->create_vendor) ?
|
||||
driver->create_vendor(driver->driver_data, io, path, config) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
RilVendor *ril_vendor_ref(RilVendor *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_VENDOR(self));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void ril_vendor_unref(RilVendor *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_VENDOR(self));
|
||||
}
|
||||
}
|
||||
|
||||
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
|
||||
struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
if (vendor && vendor->get_defaults) {
|
||||
vendor->get_defaults(defaults);
|
||||
}
|
||||
}
|
||||
|
||||
const char *ril_vendor_request_to_string(RilVendor *self, guint request)
|
||||
{
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
request_to_string(self, request) : NULL;
|
||||
}
|
||||
|
||||
const char *ril_vendor_event_to_string(RilVendor *self, guint event)
|
||||
{
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
event_to_string(self, event) : NULL;
|
||||
}
|
||||
|
||||
void ril_vendor_set_network(RilVendor *self, struct ril_network *nw)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
RIL_VENDOR_GET_CLASS(self)->set_network(self, nw);
|
||||
}
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_vendor_set_attach_apn_req(RilVendor *self, const char *apn,
|
||||
const char *user, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
set_attach_apn_req(self, apn, user, password, auth, proto) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_vendor_data_call_req(RilVendor *self, int tech,
|
||||
enum ril_data_profile profile, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
|
||||
data_call_req(self, tech, profile, apn, username, password,
|
||||
auth, proto) : NULL;
|
||||
}
|
||||
|
||||
gboolean ril_vendor_data_call_parse(RilVendor *self,
|
||||
struct ril_data_call *call, int ver, GRilIoParser *rilp)
|
||||
{
|
||||
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
|
||||
data_call_parse(self, call, ver, rilp);
|
||||
}
|
||||
|
||||
gboolean ril_vendor_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
|
||||
signal_strength_parse(self, signal_strength, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_default_set_network(RilVendor *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (self->network != network) {
|
||||
if (self->network) {
|
||||
g_object_remove_weak_pointer(G_OBJECT(self->network),
|
||||
(gpointer*) &self->network);
|
||||
}
|
||||
self->network = network;
|
||||
if (self->network) {
|
||||
g_object_add_weak_pointer(G_OBJECT(network),
|
||||
(gpointer*) &self->network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_vendor_default_id_to_string(RilVendor *self, guint id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_vendor_default_set_attach_apn_req(RilVendor *self,
|
||||
const char *apn, const char *username,
|
||||
const char *password, enum ril_auth auth,
|
||||
const char *proto)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_vendor_default_data_call_req(RilVendor *self,
|
||||
int tech, enum ril_data_profile profile,
|
||||
const char *apn, const char *user, const char *passwd,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_default_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
|
||||
{
|
||||
self->io = grilio_channel_ref(io);
|
||||
}
|
||||
|
||||
static void ril_vendor_init(RilVendor *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void ril_vendor_finalize(GObject* object)
|
||||
{
|
||||
RilVendor *self = RIL_VENDOR(object);
|
||||
|
||||
if (self->network) {
|
||||
g_object_remove_weak_pointer(G_OBJECT(self->network),
|
||||
(gpointer*) &self->network);
|
||||
}
|
||||
grilio_channel_unref(self->io);
|
||||
G_OBJECT_CLASS(ril_vendor_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_vendor_class_init(RilVendorClass* klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_vendor_finalize;
|
||||
klass->set_network = ril_vendor_default_set_network;
|
||||
klass->request_to_string = ril_vendor_default_id_to_string;
|
||||
klass->event_to_string = ril_vendor_default_id_to_string;
|
||||
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_default_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_default_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_default_signal_strength_parse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_VENDOR_H
|
||||
#define RIL_VENDOR_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_vendor_defaults {
|
||||
gboolean empty_pin_query;
|
||||
gboolean legacy_imei_query;
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean use_data_profiles;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
guint mms_data_profile_id;
|
||||
};
|
||||
|
||||
struct ril_vendor_driver {
|
||||
const char *name;
|
||||
const void *driver_data;
|
||||
void (*get_defaults)(struct ril_vendor_defaults *defaults);
|
||||
struct ril_vendor *(*create_vendor)(const void *driver_data,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *cfg);
|
||||
};
|
||||
|
||||
struct ril_vendor_signal_strength {
|
||||
gint32 gsm; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 lte; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 qdbm; /* 4*dBm, 0 if none */
|
||||
};
|
||||
|
||||
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
|
||||
struct ril_vendor *ril_vendor_create
|
||||
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||
const char *path, const struct ril_slot_config *cfg);
|
||||
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
|
||||
struct ril_vendor_defaults *defaults);
|
||||
|
||||
struct ril_vendor *ril_vendor_ref(struct ril_vendor *vendor);
|
||||
void ril_vendor_unref(struct ril_vendor *vendor);
|
||||
|
||||
const char *ril_vendor_request_to_string(struct ril_vendor *vendor,
|
||||
guint request);
|
||||
const char *ril_vendor_event_to_string(struct ril_vendor *vendor,
|
||||
guint event);
|
||||
void ril_vendor_set_network(struct ril_vendor *vendor, struct ril_network *nw);
|
||||
GRilIoRequest *ril_vendor_set_attach_apn_req(struct ril_vendor *vendor,
|
||||
const char *apn, const char *username,
|
||||
const char *password, enum ril_auth auth,
|
||||
const char *proto);
|
||||
GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
|
||||
enum ril_data_profile profile, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto);
|
||||
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean ril_vendor_signal_strength_parse(struct ril_vendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
|
||||
/* Put vendor driver descriptors to the "__vendor" section */
|
||||
#define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \
|
||||
__attribute__((used, section("__vendor"))) =
|
||||
|
||||
#endif /* RIL_VENDOR_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_VENDOR_IMPL_H
|
||||
#define RIL_VENDOR_IMPL_H
|
||||
|
||||
#include "ril_vendor.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef struct ril_vendor {
|
||||
GObject parent;
|
||||
GRilIoChannel *io;
|
||||
struct ril_network *network;
|
||||
} RilVendor;
|
||||
|
||||
typedef struct ril_vendor_class {
|
||||
GObjectClass parent;
|
||||
void (*set_network)(RilVendor *vendor, struct ril_network *network);
|
||||
const char *(*request_to_string)(RilVendor *vendor, guint request);
|
||||
const char *(*event_to_string)(RilVendor *vendor, guint event);
|
||||
GRilIoRequest *(*set_attach_apn_req)(RilVendor *vendor,
|
||||
const char *apn, const char *username,
|
||||
const char *password, enum ril_auth auth,
|
||||
const char *proto);
|
||||
GRilIoRequest *(*data_call_req)(RilVendor *vendor, int tech,
|
||||
enum ril_data_profile profile, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto);
|
||||
gboolean (*data_call_parse)(RilVendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_parse)(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
} RilVendorClass;
|
||||
|
||||
GType ril_vendor_get_type(void);
|
||||
#define RIL_VENDOR_TYPE (ril_vendor_get_type())
|
||||
#define RIL_VENDOR(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_VENDOR_TYPE, RilVendor)
|
||||
#define RIL_VENDOR_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
|
||||
RIL_VENDOR_TYPE, RilVendorClass)
|
||||
#define RIL_VENDOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
RIL_VENDOR_TYPE, RilVendorClass)
|
||||
|
||||
void ril_vendor_init_base(RilVendor *vendor, GRilIoChannel *io);
|
||||
|
||||
#endif /* RIL_VENDOR_IMPL_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,717 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_vendor.h"
|
||||
#include "ril_vendor_impl.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_queue.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/watch.h>
|
||||
#include <ofono/gprs.h>
|
||||
|
||||
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
|
||||
|
||||
enum ril_mtk_events {
|
||||
MTK_EVENT_REGISTRATION_SUSPENDED,
|
||||
MTK_EVENT_SET_ATTACH_APN,
|
||||
MTK_EVENT_PS_NETWORK_STATE_CHANGED,
|
||||
MTK_EVENT_INCOMING_CALL_INDICATION,
|
||||
MTK_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_vendor_mtk {
|
||||
RilVendor vendor;
|
||||
const struct ril_mtk_flavor *flavor;
|
||||
GRilIoQueue *q;
|
||||
struct ofono_watch *watch;
|
||||
guint set_initial_attach_apn_id;
|
||||
gboolean initial_attach_apn_ok;
|
||||
gulong ril_event_id[MTK_EVENT_COUNT];
|
||||
guint slot;
|
||||
} RilVendorMtk;
|
||||
|
||||
typedef struct ril_vendor_mtk_auto {
|
||||
RilVendorMtk mtk;
|
||||
gulong detect_id;
|
||||
} RilVendorMtkAuto;
|
||||
|
||||
typedef RilVendorClass RilVendorMtkClass;
|
||||
typedef RilVendorMtkClass RilVendorMtkAutoClass;
|
||||
|
||||
#define RIL_VENDOR_TYPE_MTK (ril_vendor_mtk_get_type())
|
||||
#define RIL_VENDOR_TYPE_MTK_AUTO (ril_vendor_mtk_auto_get_type())
|
||||
|
||||
G_DEFINE_TYPE(RilVendorMtk, ril_vendor_mtk, RIL_VENDOR_TYPE)
|
||||
G_DEFINE_TYPE(RilVendorMtkAuto, ril_vendor_mtk_auto, RIL_VENDOR_TYPE_MTK)
|
||||
|
||||
#define RIL_VENDOR_MTK(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_VENDOR_TYPE_MTK, RilVendorMtk)
|
||||
#define RIL_VENDOR_MTK_AUTO(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_VENDOR_TYPE_MTK_AUTO, RilVendorMtkAuto)
|
||||
|
||||
/* driver_data point this this: */
|
||||
struct ril_mtk_flavor {
|
||||
const char *name;
|
||||
const struct ril_mtk_msg *msg;
|
||||
void (*build_attach_apn_req_fn)(GRilIoRequest *req, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto);
|
||||
gboolean (*data_call_parse_fn)(struct ril_data_call *call,
|
||||
int version, GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_fn)(struct ril_vendor_signal_strength *sig,
|
||||
GRilIoParser *rilp);
|
||||
};
|
||||
|
||||
/* MTK specific RIL messages (actual codes differ from model to model!) */
|
||||
struct ril_mtk_msg {
|
||||
guint request_resume_registration;
|
||||
guint request_set_call_indication;
|
||||
|
||||
/* See ril_vendor_mtk_auto_detect_event */
|
||||
#define unsol_msgs unsol_ps_network_state_changed
|
||||
#define MTK_UNSOL_MSGS (4)
|
||||
|
||||
guint unsol_ps_network_state_changed;
|
||||
guint unsol_registration_suspended;
|
||||
guint unsol_incoming_call_indication;
|
||||
guint unsol_set_attach_apn;
|
||||
};
|
||||
|
||||
static const struct ril_mtk_msg msg_mtk1 = {
|
||||
.request_resume_registration = 2050,
|
||||
.request_set_call_indication = 2065,
|
||||
.unsol_ps_network_state_changed = 3012,
|
||||
.unsol_registration_suspended = 3021,
|
||||
.unsol_incoming_call_indication = 3037,
|
||||
.unsol_set_attach_apn = 3065
|
||||
};
|
||||
|
||||
static const struct ril_mtk_msg msg_mtk2 = {
|
||||
.request_resume_registration = 2065,
|
||||
.request_set_call_indication = 2086,
|
||||
.unsol_ps_network_state_changed = 3015,
|
||||
.unsol_registration_suspended = 3024,
|
||||
.unsol_incoming_call_indication = 3042,
|
||||
.unsol_set_attach_apn = 3073
|
||||
};
|
||||
|
||||
static const char *ril_vendor_mtk_request_to_string(RilVendor *vendor,
|
||||
guint request)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
|
||||
const struct ril_mtk_msg *msg = self->flavor->msg;
|
||||
|
||||
if (request == msg->request_resume_registration) {
|
||||
return "MTK_RESUME_REGISTRATION";
|
||||
} else if (request == msg->request_set_call_indication) {
|
||||
return "MTK_SET_CALL_INDICATION";
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_vendor_mtk_unsol_msg_name(const struct ril_mtk_msg *msg,
|
||||
guint event)
|
||||
{
|
||||
if (event == msg->unsol_ps_network_state_changed) {
|
||||
return "MTK_PS_NETWORK_STATE_CHANGED";
|
||||
} else if (event == msg->unsol_registration_suspended) {
|
||||
return "MTK_REGISTRATION_SUSPENDED";
|
||||
} else if (event == msg->unsol_set_attach_apn) {
|
||||
return "MTK_SET_ATTACH_APN";
|
||||
} else if (event == msg->unsol_incoming_call_indication) {
|
||||
return "MTK_INCOMING_CALL_INDICATION";
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ril_vendor_mtk_event_to_string(RilVendor *vendor,
|
||||
guint event)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
|
||||
|
||||
return ril_vendor_mtk_unsol_msg_name(self->flavor->msg, event);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
|
||||
const struct ril_mtk_msg *msg = self->flavor->msg;
|
||||
GRilIoParser rilp;
|
||||
int session_id;
|
||||
|
||||
GASSERT(id == msg->unsol_registration_suspended);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, NULL) &&
|
||||
grilio_parser_get_int32(&rilp, &session_id)) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
DBG("slot=%u,session_id=%d", self->slot, session_id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, session_id);
|
||||
grilio_queue_send_request(self->q, req,
|
||||
msg->request_resume_registration);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_build_attach_apn_req_1(GRilIoRequest *req,
|
||||
const char *apn, const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
DBG("\"%s\" %s", apn, proto);
|
||||
grilio_request_append_utf8(req, apn);
|
||||
grilio_request_append_utf8(req, proto);
|
||||
grilio_request_append_utf8(req, proto); /* roamingProtocol */
|
||||
grilio_request_append_int32(req, auth);
|
||||
grilio_request_append_utf8(req, username);
|
||||
grilio_request_append_utf8(req, password);
|
||||
grilio_request_append_utf8(req, ""); /* operatorNumeric */
|
||||
grilio_request_append_int32(req, FALSE); /* canHandleIms */
|
||||
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_build_attach_apn_req_2(GRilIoRequest *req,
|
||||
const char *apn, const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
DBG("\"%s\" %s", apn, proto);
|
||||
grilio_request_append_utf8(req, apn);
|
||||
grilio_request_append_utf8(req, proto);
|
||||
grilio_request_append_int32(req, auth);
|
||||
grilio_request_append_utf8(req, username);
|
||||
grilio_request_append_utf8(req, password);
|
||||
grilio_request_append_utf8(req, ""); /* operatorNumeric */
|
||||
grilio_request_append_int32(req, FALSE); /* canHandleIms */
|
||||
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
|
||||
int ril_status, const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
|
||||
|
||||
GASSERT(self->set_initial_attach_apn_id);
|
||||
self->set_initial_attach_apn_id = 0;
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBG("ok");
|
||||
self->initial_attach_apn_ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_initial_attach_apn_check(RilVendorMtk *self)
|
||||
{
|
||||
|
||||
if (!self->set_initial_attach_apn_id && !self->initial_attach_apn_ok) {
|
||||
struct ofono_watch *watch = self->watch;
|
||||
const struct ofono_gprs_primary_context *pc =
|
||||
ofono_gprs_context_settings_by_type(watch->gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
|
||||
if (pc) {
|
||||
const char *username;
|
||||
const char *password;
|
||||
enum ril_auth auth;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
if (pc->username[0] || pc->password[0]) {
|
||||
username = pc->username;
|
||||
password = pc->password;
|
||||
auth = ril_auth_method_from_ofono
|
||||
(pc->auth_method);
|
||||
} else {
|
||||
username = "";
|
||||
password = "";
|
||||
auth = RIL_AUTH_NONE;
|
||||
}
|
||||
|
||||
self->flavor->build_attach_apn_req_fn(req,
|
||||
pc->apn, username, password, auth,
|
||||
ril_protocol_from_ofono(pc->proto));
|
||||
grilio_request_set_timeout(req,
|
||||
SET_INITIAL_ATTACH_APN_TIMEOUT);
|
||||
self->set_initial_attach_apn_id =
|
||||
grilio_queue_send_request_full(self->q, req,
|
||||
RIL_REQUEST_SET_INITIAL_ATTACH_APN,
|
||||
ril_vendor_mtk_initial_attach_apn_resp,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
ril_vendor_mtk_initial_attach_apn_check(RIL_VENDOR_MTK(user_data));
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_ps_network_state_changed(GRilIoChannel *io,
|
||||
guint id, const void *data, guint len, void *user_data)
|
||||
{
|
||||
ril_network_query_registration_state(RIL_VENDOR(user_data)->network);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_incoming_call_indication(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
|
||||
const struct ril_mtk_msg *msg = self->flavor->msg;
|
||||
GRilIoRequest* req = NULL;
|
||||
|
||||
GASSERT(id == msg->unsol_incoming_call_indication);
|
||||
|
||||
if (msg->request_set_call_indication) {
|
||||
int nparams, cid, seq;
|
||||
gchar *call_id = NULL, *seq_no = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
|
||||
if (grilio_parser_get_int32(&rilp, &nparams) && nparams >= 5 &&
|
||||
(call_id = grilio_parser_get_utf8(&rilp)) != NULL &&
|
||||
grilio_parser_skip_string(&rilp) /* number */ &&
|
||||
grilio_parser_skip_string(&rilp) /* type */ &&
|
||||
grilio_parser_skip_string(&rilp) /* call_mode */ &&
|
||||
(seq_no = grilio_parser_get_utf8(&rilp)) != NULL &&
|
||||
gutil_parse_int(call_id, 10, &cid) &&
|
||||
gutil_parse_int(seq_no, 10, &seq)) {
|
||||
|
||||
DBG("slot=%u,cid=%d,seq=%d", self->slot, cid, seq);
|
||||
req = grilio_request_new();
|
||||
grilio_request_append_int32(req, 3); /* Param count */
|
||||
/* mode - IMS_ALLOW_INCOMING_CALL_INDICATION: */
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_append_int32(req, cid);
|
||||
grilio_request_append_int32(req, seq);
|
||||
} else {
|
||||
DBG("failed to parse INCOMING_CALL_INDICATION");
|
||||
}
|
||||
|
||||
g_free(call_id);
|
||||
g_free(seq_no);
|
||||
}
|
||||
|
||||
if (req) {
|
||||
grilio_queue_send_request(self->q, req,
|
||||
msg->request_set_call_indication);
|
||||
grilio_request_unref(req);
|
||||
} else {
|
||||
/* Let ril_voicecall.c know that something happened */
|
||||
grilio_channel_inject_unsol_event(io,
|
||||
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_vendor_mtk_data_call_req(RilVendor *vendor, int tech,
|
||||
enum ril_data_profile profile, const char *apn,
|
||||
const char *username, const char *password,
|
||||
enum ril_auth auth, const char *proto)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, 8); /* Number of parameters */
|
||||
grilio_request_append_format(req, "%d", tech);
|
||||
grilio_request_append_format(req, "%d", profile);
|
||||
grilio_request_append_utf8(req, apn);
|
||||
grilio_request_append_utf8(req, username);
|
||||
grilio_request_append_utf8(req, password);
|
||||
grilio_request_append_format(req, "%d", auth);
|
||||
grilio_request_append_utf8(req, proto);
|
||||
grilio_request_append_format(req, "%d", self->slot+1);
|
||||
return req;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_vendor_mtk_set_attach_apn_req(RilVendor *vendor,
|
||||
const char *apn, const char *user, const char *pass,
|
||||
enum ril_auth auth, const char *prot)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
self->flavor->build_attach_apn_req_fn(req, apn, user, pass, auth, prot);
|
||||
return req;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_data_call *call,
|
||||
int version, GRilIoParser *rilp)
|
||||
{
|
||||
if (version < 11) {
|
||||
int prot;
|
||||
char *prot_str;
|
||||
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
|
||||
guint32 active = RIL_DATA_CALL_INACTIVE;
|
||||
|
||||
/* RIL_Data_Call_Response_v6 with MTK specific additions */
|
||||
grilio_parser_get_uint32(rilp, &status);
|
||||
grilio_parser_get_int32(rilp, &call->retry_time);
|
||||
grilio_parser_get_int32(rilp, &call->cid);
|
||||
grilio_parser_get_uint32(rilp, &active);
|
||||
grilio_parser_get_int32(rilp, &call->mtu); /* MTK specific */
|
||||
prot_str = grilio_parser_get_utf8(rilp);
|
||||
prot = ril_protocol_to_ofono(prot_str);
|
||||
g_free(prot_str);
|
||||
|
||||
if (prot >= 0) {
|
||||
call->ifname = grilio_parser_get_utf8(rilp);
|
||||
call->addresses = grilio_parser_split_utf8(rilp, " ");
|
||||
call->dnses = grilio_parser_split_utf8(rilp, " ");
|
||||
call->gateways = grilio_parser_split_utf8(rilp, " ");
|
||||
if (call->ifname && call->addresses) {
|
||||
call->prot = prot;
|
||||
call->status = status;
|
||||
call->active = active;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_data_call_parse(RilVendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
|
||||
|
||||
return flavor->data_call_parse_fn ?
|
||||
flavor->data_call_parse_fn(call, version, rilp) :
|
||||
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
|
||||
data_call_parse(vendor, call, version, rilp);
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_1
|
||||
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
|
||||
{
|
||||
if (grilio_parser_bytes_remaining(rilp) == 64) {
|
||||
gint32 rsrp = 0, rssi = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->gsm);
|
||||
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->lte);
|
||||
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(rilp, NULL); /* cqi */
|
||||
|
||||
/* ???? */
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
grilio_parser_get_int32(rilp, &rssi);
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
|
||||
signal->qdbm = (rssi > 0 && rssi != INT_MAX) ? (-4 * rssi) :
|
||||
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_2
|
||||
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
|
||||
{
|
||||
if (grilio_parser_bytes_remaining(rilp) == 64) {
|
||||
gint32 rsrp = 0, is_gsm = 0, rssi_qdbm = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->gsm);
|
||||
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->lte);
|
||||
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(rilp, NULL); /* cqi */
|
||||
|
||||
/* WCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &is_gsm); /* isGsm */
|
||||
grilio_parser_get_int32(rilp, &rssi_qdbm); /* rssiQdbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rscpQdbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* Ecn0Qdbm*/
|
||||
|
||||
signal->qdbm = (is_gsm == 1 && rssi_qdbm < 0) ? rssi_qdbm :
|
||||
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_parse(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
|
||||
|
||||
return flavor->signal_strength_fn ?
|
||||
flavor->signal_strength_fn(signal, rilp) :
|
||||
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
|
||||
signal_strength_parse(vendor, signal, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
/*
|
||||
* With most Qualcomm RIL implementations, querying available band
|
||||
* modes causes some magic Android properties to appear. Otherwise
|
||||
* this request is pretty harmless and useless.
|
||||
*
|
||||
* Most MediaTek RIL implementations don't support this request and
|
||||
* don't even bother to reply which slows things down because we wait
|
||||
* for this request to complete at startup.
|
||||
*/
|
||||
defaults->query_available_band_mode = FALSE;
|
||||
defaults->empty_pin_query = FALSE;
|
||||
defaults->legacy_imei_query = TRUE;
|
||||
defaults->force_gsm_when_radio_off = FALSE;
|
||||
defaults->replace_strange_oper = TRUE;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_base_init(RilVendorMtk *self, GRilIoChannel *io,
|
||||
const char *path, const struct ril_slot_config *config)
|
||||
{
|
||||
ril_vendor_init_base(&self->vendor, io);
|
||||
self->q = grilio_queue_new(io);
|
||||
self->watch = ofono_watch_new(path);
|
||||
self->slot = config->slot;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_set_flavor(RilVendorMtk *self,
|
||||
const struct ril_mtk_flavor *flavor)
|
||||
{
|
||||
GRilIoChannel *io = self->vendor.io;
|
||||
const struct ril_mtk_msg *msg = flavor->msg;
|
||||
|
||||
grilio_channel_remove_all_handlers(io, self->ril_event_id);
|
||||
self->flavor = flavor;
|
||||
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_vendor_mtk_registration_suspended,
|
||||
msg->unsol_registration_suspended, self);
|
||||
if (msg->unsol_set_attach_apn) {
|
||||
self->ril_event_id[MTK_EVENT_SET_ATTACH_APN] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_vendor_mtk_set_attach_apn,
|
||||
msg->unsol_set_attach_apn, self);
|
||||
}
|
||||
if (msg->unsol_ps_network_state_changed) {
|
||||
self->ril_event_id[MTK_EVENT_PS_NETWORK_STATE_CHANGED] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_vendor_mtk_ps_network_state_changed,
|
||||
msg->unsol_ps_network_state_changed, self);
|
||||
}
|
||||
if (msg->unsol_incoming_call_indication) {
|
||||
self->ril_event_id[MTK_EVENT_INCOMING_CALL_INDICATION] =
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_vendor_mtk_incoming_call_indication,
|
||||
msg->unsol_incoming_call_indication, self);
|
||||
}
|
||||
}
|
||||
|
||||
static RilVendor *ril_vendor_mtk_create_from_data(const void *driver_data,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
const struct ril_mtk_flavor *flavor = driver_data;
|
||||
RilVendorMtk *mtk = g_object_new(RIL_VENDOR_TYPE_MTK, NULL);
|
||||
|
||||
ril_vendor_mtk_base_init(mtk, io, path, config);
|
||||
ril_vendor_mtk_set_flavor(mtk, flavor);
|
||||
DBG("%s slot %u", flavor->name, mtk->slot);
|
||||
return &mtk->vendor;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_init(RilVendorMtk *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_finalize(GObject* object)
|
||||
{
|
||||
RilVendorMtk *self = RIL_VENDOR_MTK(object);
|
||||
RilVendor *vendor = &self->vendor;
|
||||
|
||||
DBG("slot %u", self->slot);
|
||||
grilio_queue_cancel_all(self->q, FALSE);
|
||||
grilio_queue_unref(self->q);
|
||||
ofono_watch_unref(self->watch);
|
||||
grilio_channel_remove_all_handlers(vendor->io, self->ril_event_id);
|
||||
G_OBJECT_CLASS(ril_vendor_mtk_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_class_init(RilVendorMtkClass* klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_vendor_mtk_finalize;
|
||||
klass->request_to_string = ril_vendor_mtk_request_to_string;
|
||||
klass->event_to_string = ril_vendor_mtk_event_to_string;
|
||||
klass->set_attach_apn_req = ril_vendor_mtk_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_mtk_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_mtk_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_mtk_signal_strength_parse;
|
||||
}
|
||||
|
||||
static const struct ril_mtk_flavor ril_mtk_flavor1 = {
|
||||
.name = "mtk1",
|
||||
.msg = &msg_mtk1,
|
||||
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_1,
|
||||
.data_call_parse_fn = NULL,
|
||||
.signal_strength_fn = &ril_vendor_mtk_signal_strength_1
|
||||
};
|
||||
|
||||
static const struct ril_mtk_flavor ril_mtk_flavor2 = {
|
||||
.name = "mtk2",
|
||||
.msg = &msg_mtk2,
|
||||
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_2,
|
||||
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6,
|
||||
.signal_strength_fn = &ril_vendor_mtk_signal_strength_2
|
||||
};
|
||||
|
||||
#define DEFAULT_MTK_TYPE (&ril_mtk_flavor1)
|
||||
|
||||
static const struct ril_mtk_flavor *mtk_flavors [] = {
|
||||
&ril_mtk_flavor1,
|
||||
&ril_mtk_flavor2
|
||||
};
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk1) {
|
||||
.name = "mtk1",
|
||||
.driver_data = &ril_mtk_flavor1,
|
||||
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||
.create_vendor = ril_vendor_mtk_create_from_data
|
||||
};
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk2) {
|
||||
.name = "mtk2",
|
||||
.driver_data = &ril_mtk_flavor2,
|
||||
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||
.create_vendor = ril_vendor_mtk_create_from_data
|
||||
};
|
||||
|
||||
/* Auto-selection */
|
||||
|
||||
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
RilVendorMtkAuto *self = RIL_VENDOR_MTK_AUTO(user_data);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(mtk_flavors); i++) {
|
||||
const struct ril_mtk_flavor *flavor = mtk_flavors[i];
|
||||
const struct ril_mtk_msg *msg = flavor->msg;
|
||||
const guint *ids = &msg->unsol_msgs;
|
||||
guint j;
|
||||
|
||||
for (j = 0; j < MTK_UNSOL_MSGS; j++) {
|
||||
if (ids[j] == id) {
|
||||
DBG("event %u is %s %s", id, flavor->name,
|
||||
ril_vendor_mtk_unsol_msg_name(msg,id));
|
||||
ril_vendor_mtk_set_flavor(&self->mtk, flavor);
|
||||
/* We are done */
|
||||
grilio_channel_remove_handler(io,
|
||||
self->detect_id);
|
||||
self->detect_id = 0;
|
||||
/* And repeat the event to invoke the handler */
|
||||
grilio_channel_inject_unsol_event(io, id,
|
||||
data, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_auto_init(RilVendorMtkAuto *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_auto_finalize(GObject* object)
|
||||
{
|
||||
RilVendorMtkAuto *self = RIL_VENDOR_MTK_AUTO(object);
|
||||
|
||||
DBG("slot %u", self->mtk.slot);
|
||||
grilio_channel_remove_handler(self->mtk.vendor.io, self->detect_id);
|
||||
G_OBJECT_CLASS(ril_vendor_mtk_auto_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_auto_class_init(RilVendorMtkAutoClass* klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_vendor_mtk_auto_finalize;
|
||||
}
|
||||
|
||||
static RilVendor *ril_vendor_mtk_auto_create_vendor(const void *driver_data,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
RilVendorMtkAuto *self = g_object_new(RIL_VENDOR_TYPE_MTK_AUTO, NULL);
|
||||
RilVendorMtk *mtk = &self->mtk;
|
||||
|
||||
ril_vendor_mtk_base_init(mtk, io, path, config);
|
||||
ril_vendor_mtk_set_flavor(mtk, DEFAULT_MTK_TYPE);
|
||||
DBG("%s slot %u", mtk->flavor->name, mtk->slot);
|
||||
|
||||
/*
|
||||
* Subscribe for (all) unsolicited events. Keep on listening until
|
||||
* we receive an MTK specific event that tells us which particular
|
||||
* kind of MTK adaptation we are using.
|
||||
*/
|
||||
self->detect_id = grilio_channel_add_unsol_event_handler(io,
|
||||
ril_vendor_mtk_auto_detect_event, 0, self);
|
||||
return &mtk->vendor;
|
||||
}
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {
|
||||
.name = "mtk",
|
||||
.get_defaults = ril_vendor_mtk_get_defaults,
|
||||
.create_vendor = ril_vendor_mtk_auto_create_vendor
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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 "drivers/ril/ril_config.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define TMP_DIR_TEMPLATE "test-ril_config-XXXXXX"
|
||||
|
||||
static void test_get_value(const char *conf, void (*test)(GKeyFile *k))
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/test.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_assert(g_file_set_contents(file, conf, -1, NULL));
|
||||
g_assert(g_key_file_load_from_file(k, file, 0, NULL));
|
||||
|
||||
DBG("%s:\n%s", file, conf);
|
||||
test(k);
|
||||
|
||||
remove(file);
|
||||
remove(dir);
|
||||
|
||||
g_key_file_unref(k);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== get_ints ==== */
|
||||
|
||||
static void test_get_ints_cb(GKeyFile *k)
|
||||
{
|
||||
GUtilInts *ints;
|
||||
const int* data;
|
||||
guint count;
|
||||
|
||||
g_assert(!ril_config_get_ints(k, "g1", "k1"));
|
||||
g_assert(!ril_config_get_ints(k, "g", "k2")); /* Empty */
|
||||
|
||||
ints = ril_config_get_ints(k, "g", "k");
|
||||
data = gutil_ints_get_data(ints, &count);
|
||||
g_assert(count == 2);
|
||||
g_assert(data[0] == 0);
|
||||
g_assert(data[1] == 1);
|
||||
gutil_ints_unref(ints);
|
||||
|
||||
ints = ril_config_get_ints(k, "g", "k1");
|
||||
data = gutil_ints_get_data(ints, &count);
|
||||
g_assert(count == 3);
|
||||
g_assert(data[0] == 2);
|
||||
g_assert(data[1] == 3);
|
||||
g_assert(data[2] == 4);
|
||||
gutil_ints_unref(ints);
|
||||
}
|
||||
|
||||
static void test_get_ints(void)
|
||||
{
|
||||
static const char conf [] =
|
||||
"[" RILCONF_SETTINGS_GROUP "]\nk = 0, 1, x\n"
|
||||
"[g]\nk1=2,3,4 # comment\nk2=\n";
|
||||
|
||||
test_get_value(conf, test_get_ints_cb);
|
||||
}
|
||||
|
||||
/* ==== ints_to_string ==== */
|
||||
|
||||
static void test_ints_to_string(void)
|
||||
{
|
||||
static const int data[] = { 1, 2 };
|
||||
GUtilInts* ints = gutil_ints_new_static(data, G_N_ELEMENTS(data));
|
||||
char *str = ril_config_ints_to_string(ints, ',');
|
||||
g_assert(!g_strcmp0(str, "1,2"));
|
||||
g_free(str);
|
||||
gutil_ints_unref(ints);
|
||||
|
||||
g_assert(!ril_config_ints_to_string(NULL, 0));
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_config/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-ril_config",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("get_ints"), test_get_ints);
|
||||
g_test_add_func(TEST_("ints_to_string"), test_ints_to_string);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,326 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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 "drivers/ril/ril_ecclist.h"
|
||||
#include "drivers/ril/ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define TMP_DIR_TEMPLATE "test-ril_ecclist-XXXXXX"
|
||||
#define TEST_TIMEOUT_SEC (20)
|
||||
|
||||
GLOG_MODULE_DEFINE("rilmodem");
|
||||
|
||||
static gboolean test_debug = FALSE;
|
||||
|
||||
struct ril_ecclist_parse_test {
|
||||
const char* name;
|
||||
const char* in;
|
||||
const char* const* out;
|
||||
};
|
||||
|
||||
static gboolean test_timeout_cb(gpointer user_data)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean test_idle_quit_cb(gpointer loop)
|
||||
{
|
||||
g_main_loop_quit(loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void test_quit_cb(struct ril_ecclist *ecc, gpointer loop)
|
||||
{
|
||||
g_idle_add(test_idle_quit_cb, loop);
|
||||
}
|
||||
|
||||
static void test_inc_cb(struct ril_ecclist *ecc, gpointer ptr)
|
||||
{
|
||||
(*(int*)ptr)++;
|
||||
}
|
||||
|
||||
/* ==== parse ==== */
|
||||
|
||||
static void test_parse(gconstpointer data)
|
||||
{
|
||||
const struct ril_ecclist_parse_test *test = data;
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
struct ril_ecclist *ecc;
|
||||
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, test->in, -1, NULL));
|
||||
ecc = ril_ecclist_new(file);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)test->out));
|
||||
|
||||
ril_ecclist_unref(ecc);
|
||||
remove(file);
|
||||
remove(dir);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
static const char* null_str = NULL;
|
||||
static const char single_str_in[] = "911";
|
||||
static const char* single_str_out[] = { "911", NULL };
|
||||
static const char double_str_in[] = "911,112";
|
||||
static const char double2_str_in[] = "911, 112,";
|
||||
static const char double3_str_in[] = "911, 911, 112 ";
|
||||
static const char* double_str_out[] = { "112", "911", NULL };
|
||||
static const char mtk_str_in[] = "112,31;911,31;112,-1;911,-1";
|
||||
static const char mtk2_str_in[] = "112,31; 911,31; 112; 911 ";
|
||||
|
||||
static const struct ril_ecclist_parse_test tests[] = {
|
||||
{ "empty", "", &null_str },
|
||||
{ "single", single_str_in, single_str_out },
|
||||
{ "double", double_str_in, double_str_out },
|
||||
{ "double2", double2_str_in, double_str_out },
|
||||
{ "double3", double3_str_in, double_str_out },
|
||||
{ "mtk", mtk_str_in, double_str_out },
|
||||
{ "mtk2", mtk2_str_in, double_str_out }
|
||||
};
|
||||
|
||||
/* ==== file_perm ==== */
|
||||
|
||||
static void test_file_perm()
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
int count = 0;
|
||||
struct ril_ecclist *ecc;
|
||||
gulong id[2];
|
||||
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
guint test_timeout_id = test_debug ? 0 :
|
||||
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
|
||||
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
ecc = ril_ecclist_new(file);
|
||||
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
|
||||
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
|
||||
|
||||
g_assert(id[0]);
|
||||
g_assert(id[1]);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
|
||||
|
||||
/* Modify the file */
|
||||
g_assert(g_file_set_contents(file, double_str_in, -1, NULL));
|
||||
|
||||
/* ril_ecclist needs event loop to process filesystem change events */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
g_assert(count == 1);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)double_str_out));
|
||||
|
||||
/* Making file unreadable resets the ecc list */
|
||||
GDEBUG("Making file %s unreadable", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
g_assert(chmod(file, 0) == 0);
|
||||
count = 0;
|
||||
g_main_loop_run(loop);
|
||||
g_assert(count == 1);
|
||||
g_assert(!ecc->list);
|
||||
|
||||
if (test_timeout_id) {
|
||||
g_source_remove(test_timeout_id);
|
||||
}
|
||||
g_main_loop_unref(loop);
|
||||
ril_ecclist_remove_handler(ecc, id[0]);
|
||||
ril_ecclist_remove_handler(ecc, id[1]);
|
||||
ril_ecclist_unref(ecc);
|
||||
remove(dir);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== file_change ==== */
|
||||
|
||||
static void test_file_change()
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
int count = 0;
|
||||
struct ril_ecclist *ecc;
|
||||
gulong id[2];
|
||||
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
guint test_timeout_id = test_debug ? 0 :
|
||||
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
|
||||
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
ecc = ril_ecclist_new(file);
|
||||
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
|
||||
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
|
||||
|
||||
g_assert(id[0]);
|
||||
g_assert(id[1]);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
|
||||
|
||||
/* Modify the file */
|
||||
g_assert(g_file_set_contents(file, double_str_in, -1, NULL));
|
||||
|
||||
/* ril_ecclist needs event loop to process filesystem change events */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
g_assert(count == 1);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)double_str_out));
|
||||
|
||||
/* Removing the file resets the ecc list */
|
||||
GDEBUG("Removing file %s", file);
|
||||
g_assert(remove(file) == 0);
|
||||
count = 0;
|
||||
g_main_loop_run(loop);
|
||||
g_assert(count == 1);
|
||||
g_assert(!ecc->list);
|
||||
|
||||
if (test_timeout_id) {
|
||||
g_source_remove(test_timeout_id);
|
||||
}
|
||||
g_main_loop_unref(loop);
|
||||
ril_ecclist_remove_handler(ecc, id[0]);
|
||||
ril_ecclist_remove_handler(ecc, id[1]);
|
||||
ril_ecclist_unref(ecc);
|
||||
remove(dir);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== dir_change ==== */
|
||||
|
||||
static void test_dir_change()
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
int count = 0;
|
||||
struct ril_ecclist *ecc;
|
||||
gulong id[3];
|
||||
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
guint test_timeout_id = test_debug ? 0 :
|
||||
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
|
||||
|
||||
GDEBUG("Created directory %s", dir);
|
||||
ecc = ril_ecclist_new(file);
|
||||
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
|
||||
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
|
||||
|
||||
g_assert(id[0]);
|
||||
g_assert(id[1]);
|
||||
g_assert(!ecc->list);
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
|
||||
/* ril_ecclist needs event loop to process filesystem change events */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
g_assert(count == 1);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
|
||||
|
||||
/* Removing the directory resets the ecc list */
|
||||
GDEBUG("Removing directory %s", dir);
|
||||
g_assert(remove(file) == 0);
|
||||
g_assert(remove(dir) == 0);
|
||||
count = 0;
|
||||
g_main_loop_run(loop);
|
||||
g_assert(count == 1);
|
||||
g_assert(!ecc->list);
|
||||
|
||||
if (test_timeout_id) {
|
||||
g_source_remove(test_timeout_id);
|
||||
}
|
||||
g_main_loop_unref(loop);
|
||||
ril_ecclist_remove_handler(ecc, id[0]);
|
||||
ril_ecclist_remove_handler(ecc, id[1]);
|
||||
ril_ecclist_unref(ecc);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== null ==== */
|
||||
|
||||
static void test_null(void)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
struct ril_ecclist *ecc;
|
||||
|
||||
/* Make sure neither directory nor file exist */
|
||||
remove(dir);
|
||||
ecc = ril_ecclist_new(file);
|
||||
g_assert(ecc);
|
||||
g_assert(!ecc->list);
|
||||
g_assert(!ril_ecclist_new(NULL));
|
||||
g_assert(!ril_ecclist_ref(NULL));
|
||||
g_assert(!ril_ecclist_add_list_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!ril_ecclist_add_list_changed_handler(ecc, NULL, NULL));
|
||||
ril_ecclist_unref(NULL);
|
||||
ril_ecclist_remove_handler(NULL, 0);
|
||||
ril_ecclist_remove_handler(ecc, 0);
|
||||
ril_ecclist_unref(ril_ecclist_ref(ecc));
|
||||
ril_ecclist_unref(ecc);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_ecclist/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.name = "test-ril_ecclist";
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init(gutil_log_default.name,
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
if (argc > 1 && !strcmp(argv[1] , "-d")) {
|
||||
test_debug = TRUE;
|
||||
GDEBUG("Debugging on (no timeout)");
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(tests); i++) {
|
||||
const struct ril_ecclist_parse_test* test = tests + i;
|
||||
char* path = g_strconcat(TEST_("parse/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_parse);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("file_perm"), test_file_perm);
|
||||
g_test_add_func(TEST_("file_change"), test_file_change);
|
||||
g_test_add_func(TEST_("dir_change"), test_dir_change);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2021 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 "drivers/ril/ril_util.h"
|
||||
|
||||
#include <ofono/netreg.h>
|
||||
|
||||
#define RIL_PROTO_IP_STR "IP"
|
||||
#define RIL_PROTO_IPV6_STR "IPV6"
|
||||
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
|
||||
|
||||
static void test_parse_tech(void)
|
||||
{
|
||||
int tech = -2;
|
||||
|
||||
g_assert_cmpint(ril_parse_tech(NULL, NULL), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_NONE);
|
||||
g_assert_cmpint(ril_parse_tech(NULL, &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_NONE);
|
||||
g_assert_cmpint(tech, == ,-1);
|
||||
g_assert_cmpint(ril_parse_tech("-1", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_NONE);
|
||||
g_assert_cmpint(tech, == ,-1);
|
||||
g_assert_cmpint(ril_parse_tech("0", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_NONE);
|
||||
g_assert_cmpint(tech, == ,0);
|
||||
g_assert_cmpint(ril_parse_tech("1", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_GSM);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_GPRS);
|
||||
g_assert_cmpint(ril_parse_tech("16", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_GSM);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_GSM);
|
||||
g_assert_cmpint(ril_parse_tech("2", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_GSM_EGPRS);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_EDGE);
|
||||
g_assert_cmpint(ril_parse_tech("3", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_UTRAN);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_UMTS);
|
||||
g_assert_cmpint(ril_parse_tech("9", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_HSDPA);
|
||||
g_assert_cmpint(ril_parse_tech("10", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_HSUPA);
|
||||
g_assert_cmpint(ril_parse_tech("11", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_HSPA);
|
||||
g_assert_cmpint(ril_parse_tech("15", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_HSPAP);
|
||||
g_assert_cmpint(ril_parse_tech("14", &tech), == ,
|
||||
OFONO_ACCESS_TECHNOLOGY_EUTRAN);
|
||||
g_assert_cmpint(tech, == ,RADIO_TECH_LTE);
|
||||
}
|
||||
|
||||
static void test_parse_mcc_mnc(void)
|
||||
{
|
||||
struct ofono_network_operator op;
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
g_assert(!ril_parse_mcc_mnc(NULL, &op));
|
||||
g_assert(!ril_parse_mcc_mnc("", &op));
|
||||
g_assert(!ril_parse_mcc_mnc("24x", &op));
|
||||
g_assert(!ril_parse_mcc_mnc("244", &op));
|
||||
g_assert(!ril_parse_mcc_mnc("244x", &op));
|
||||
g_assert(ril_parse_mcc_mnc("24412", &op));
|
||||
g_assert_cmpstr(op.mcc, == ,"244");
|
||||
g_assert_cmpstr(op.mnc, == ,"12");
|
||||
g_assert(!op.tech);
|
||||
g_assert(ril_parse_mcc_mnc("25001+", &op));
|
||||
g_assert_cmpstr(op.mcc, == ,"250");
|
||||
g_assert_cmpstr(op.mnc, == ,"01");
|
||||
g_assert(!op.tech);
|
||||
g_assert(ril_parse_mcc_mnc("25503+14", &op));
|
||||
g_assert_cmpstr(op.mcc, == ,"255");
|
||||
g_assert_cmpstr(op.mnc, == ,"03");
|
||||
g_assert_cmpint(op.tech, == ,OFONO_ACCESS_TECHNOLOGY_EUTRAN);
|
||||
/* Not sure if this is right but that's now it currently works: */
|
||||
op.tech = 0;
|
||||
g_assert(ril_parse_mcc_mnc("3101500", &op));
|
||||
g_assert_cmpstr(op.mcc, == ,"310");
|
||||
g_assert_cmpstr(op.mnc, == ,"150");
|
||||
g_assert(!op.tech);
|
||||
}
|
||||
|
||||
static void test_protocol_from_ofono(void)
|
||||
{
|
||||
g_assert_cmpstr(ril_protocol_from_ofono(OFONO_GPRS_PROTO_IP), == ,
|
||||
RIL_PROTO_IP_STR);
|
||||
g_assert_cmpstr(ril_protocol_from_ofono(OFONO_GPRS_PROTO_IPV6), == ,
|
||||
RIL_PROTO_IPV6_STR);
|
||||
g_assert_cmpstr(ril_protocol_from_ofono(OFONO_GPRS_PROTO_IPV4V6), == ,
|
||||
RIL_PROTO_IPV4V6_STR);
|
||||
g_assert(!ril_protocol_from_ofono((enum ofono_gprs_proto)-1));
|
||||
}
|
||||
|
||||
static void test_protocol_to_ofono(void)
|
||||
{
|
||||
g_assert(ril_protocol_to_ofono(NULL) < 0);
|
||||
g_assert(ril_protocol_to_ofono("") < 0);
|
||||
g_assert(ril_protocol_to_ofono("ip") < 0);
|
||||
g_assert(ril_protocol_to_ofono(RIL_PROTO_IP_STR) ==
|
||||
OFONO_GPRS_PROTO_IP);
|
||||
g_assert(ril_protocol_to_ofono(RIL_PROTO_IPV6_STR) ==
|
||||
OFONO_GPRS_PROTO_IPV6);
|
||||
g_assert(ril_protocol_to_ofono(RIL_PROTO_IPV4V6_STR) ==
|
||||
OFONO_GPRS_PROTO_IPV4V6);
|
||||
}
|
||||
|
||||
static void test_auth_method(void)
|
||||
{
|
||||
g_assert(ril_auth_method_from_ofono(OFONO_GPRS_AUTH_METHOD_NONE) ==
|
||||
RIL_AUTH_NONE);
|
||||
g_assert(ril_auth_method_from_ofono(OFONO_GPRS_AUTH_METHOD_CHAP) ==
|
||||
RIL_AUTH_CHAP);
|
||||
g_assert(ril_auth_method_from_ofono(OFONO_GPRS_AUTH_METHOD_PAP) ==
|
||||
RIL_AUTH_PAP);
|
||||
g_assert(ril_auth_method_from_ofono(OFONO_GPRS_AUTH_METHOD_ANY) ==
|
||||
RIL_AUTH_BOTH);
|
||||
g_assert(ril_auth_method_from_ofono((enum ofono_gprs_auth_method)-1) ==
|
||||
RIL_AUTH_BOTH);
|
||||
}
|
||||
|
||||
static void test_strings(void)
|
||||
{
|
||||
g_assert_cmpstr(ril_error_to_string(RIL_E_SUCCESS), == ,"OK");
|
||||
g_assert_cmpstr(ril_error_to_string(2147483647), == ,"2147483647");
|
||||
g_assert_cmpstr(ril_request_to_string(RIL_RESPONSE_ACKNOWLEDGEMENT),==,
|
||||
"RESPONSE_ACK");
|
||||
g_assert_cmpstr(ril_request_to_string(2147483647), == ,
|
||||
"RIL_REQUEST_2147483647");
|
||||
g_assert_cmpstr(ril_unsol_event_to_string(2147483647), == ,
|
||||
"RIL_UNSOL_2147483647");
|
||||
g_assert_cmpstr(ril_radio_state_to_string(2147483647), == ,
|
||||
"2147483647 (?)");
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_util/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-ril_util",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("parse_tech"), test_parse_tech);
|
||||
g_test_add_func(TEST_("parse_mcc_mnc"), test_parse_mcc_mnc);
|
||||
g_test_add_func(TEST_("protocol_from_ofono"), test_protocol_from_ofono);
|
||||
g_test_add_func(TEST_("protocol_to_ofono"), test_protocol_to_ofono);
|
||||
g_test_add_func(TEST_("auth_method"), test_auth_method);
|
||||
g_test_add_func(TEST_("strings"), test_strings);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,394 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2019 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 "drivers/ril/ril_vendor.h"
|
||||
#include "drivers/ril/ril_vendor_impl.h"
|
||||
#include "drivers/ril/ril_network.h"
|
||||
#include "drivers/ril/ril_data.h"
|
||||
#include "drivers/ril/ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
GLOG_MODULE_DEFINE("ril");
|
||||
|
||||
/* Stubs */
|
||||
typedef struct ril_network TestNetwork;
|
||||
typedef GObjectClass TestNetworkClass;
|
||||
static void test_network_init(TestNetwork *self) {}
|
||||
static void test_network_class_init(TestNetworkClass *klass) {}
|
||||
G_DEFINE_TYPE(TestNetwork, test_network, G_TYPE_OBJECT)
|
||||
|
||||
void ril_network_query_registration_state(struct ril_network *network)
|
||||
{
|
||||
}
|
||||
|
||||
const struct ofono_gprs_primary_context *ofono_gprs_context_settings_by_type
|
||||
(struct ofono_gprs *gprs, enum ofono_gprs_context_type type)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Test vendor objects and drivers */
|
||||
|
||||
typedef RilVendor TestVendor;
|
||||
typedef RilVendorClass TestVendorClass;
|
||||
static void test_vendor_init(TestVendor *self) {}
|
||||
static void test_vendor_class_init(TestVendorClass* klass) {}
|
||||
static const struct ril_vendor_defaults test_defaults = { .enable_cbs = TRUE };
|
||||
G_DEFINE_TYPE(TestVendor, test_vendor, RIL_VENDOR_TYPE)
|
||||
|
||||
static void test_driver_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
memcpy(defaults, &test_defaults, sizeof(*defaults));
|
||||
}
|
||||
|
||||
static RilVendor *test_driver_create_vendor(const void *driver_data,
|
||||
GRilIoChannel *io, const char *path,
|
||||
const struct ril_slot_config *config)
|
||||
{
|
||||
TestVendor *self = g_object_new(test_vendor_get_type(), NULL);
|
||||
|
||||
ril_vendor_init_base(self, io);
|
||||
return self;
|
||||
}
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(test_driver) {
|
||||
.name = "test",
|
||||
.get_defaults = test_driver_get_defaults,
|
||||
.create_vendor = test_driver_create_vendor
|
||||
};
|
||||
|
||||
RIL_VENDOR_DRIVER_DEFINE(dummy_driver) { .name = "dummy" };
|
||||
|
||||
/* Tests */
|
||||
|
||||
static void test_null(void)
|
||||
{
|
||||
ril_vendor_unref(NULL);
|
||||
ril_vendor_set_network(NULL, NULL);
|
||||
ril_vendor_data_call_parse(NULL, NULL, 0, NULL);
|
||||
ril_vendor_get_defaults(NULL, NULL);
|
||||
g_assert(!ril_vendor_find_driver(NULL));
|
||||
g_assert(!ril_vendor_create(NULL, NULL, NULL, NULL));
|
||||
g_assert(!ril_vendor_ref(NULL));
|
||||
g_assert(!ril_vendor_request_to_string(NULL, 0));
|
||||
g_assert(!ril_vendor_event_to_string(NULL, 0));
|
||||
g_assert(!ril_vendor_set_attach_apn_req(NULL, NULL, NULL, NULL,
|
||||
RIL_AUTH_NONE, NULL));
|
||||
g_assert(!ril_vendor_data_call_req(NULL, 0, RIL_DATA_PROFILE_DEFAULT,
|
||||
NULL, NULL, NULL, RIL_AUTH_NONE, NULL));
|
||||
}
|
||||
|
||||
static void test_drivers(void)
|
||||
{
|
||||
const struct ril_vendor_driver *driver;
|
||||
struct ril_vendor_defaults defaults;
|
||||
|
||||
/* This one exists and has all the callbacks */
|
||||
driver = ril_vendor_find_driver(test_driver.name);
|
||||
g_assert(driver);
|
||||
memset(&defaults, 0, sizeof(defaults));
|
||||
ril_vendor_get_defaults(driver, &defaults);
|
||||
g_assert(!memcmp(&defaults, &test_defaults, sizeof(defaults)));
|
||||
|
||||
/* This one has no callbacks at all */
|
||||
driver = ril_vendor_find_driver(dummy_driver.name);
|
||||
g_assert(driver);
|
||||
memset(&defaults, 0, sizeof(defaults));
|
||||
g_assert(!ril_vendor_create(driver, NULL, NULL, NULL));
|
||||
ril_vendor_get_defaults(driver, &defaults);
|
||||
|
||||
/* And this one doesn't exist */
|
||||
g_assert(!ril_vendor_find_driver("no such driver"));
|
||||
}
|
||||
|
||||
static void test_base(void)
|
||||
{
|
||||
TestNetwork *network = g_object_new(test_network_get_type(), NULL);
|
||||
const struct ril_vendor_driver *driver;
|
||||
struct ril_vendor *base;
|
||||
|
||||
/* Create test vendor which does nothing but extends the base */
|
||||
driver = ril_vendor_find_driver(test_driver.name);
|
||||
g_assert(driver);
|
||||
base = ril_vendor_create(driver, NULL, NULL, NULL);
|
||||
ril_vendor_set_network(base, NULL);
|
||||
ril_vendor_set_network(base, network);
|
||||
ril_vendor_set_network(base, NULL);
|
||||
ril_vendor_set_network(base, network);
|
||||
|
||||
g_assert(!ril_vendor_request_to_string(base, 0));
|
||||
g_assert(!ril_vendor_event_to_string(base, 0));
|
||||
g_assert(!ril_vendor_set_attach_apn_req(base, NULL, NULL, NULL,
|
||||
RIL_AUTH_NONE, NULL));
|
||||
g_assert(!ril_vendor_data_call_req(base, 0, RIL_DATA_PROFILE_DEFAULT,
|
||||
NULL, NULL, NULL, RIL_AUTH_NONE, NULL));
|
||||
g_assert(!ril_vendor_data_call_parse(base, NULL, 0, NULL));
|
||||
|
||||
g_assert(ril_vendor_ref(base) == base);
|
||||
ril_vendor_unref(base);
|
||||
ril_vendor_unref(base);
|
||||
g_object_unref(network);
|
||||
}
|
||||
|
||||
static void test_mtk(void)
|
||||
{
|
||||
TestNetwork *network = g_object_new(test_network_get_type(), NULL);
|
||||
const struct ril_vendor_driver *driver = ril_vendor_find_driver("mtk");
|
||||
struct ril_vendor_defaults defaults;
|
||||
struct ril_slot_config config;
|
||||
struct ril_vendor *mtk;
|
||||
|
||||
g_assert(driver);
|
||||
memset(&defaults, 0, sizeof(defaults));
|
||||
memset(&config, 0, sizeof(config));
|
||||
ril_vendor_get_defaults(driver, &defaults);
|
||||
mtk = ril_vendor_create(driver, NULL, NULL, &config);
|
||||
g_assert(mtk);
|
||||
|
||||
/* Freeing the network clears vendor's weak pointer */
|
||||
ril_vendor_set_network(mtk, network);
|
||||
g_object_unref(network);
|
||||
g_assert(!ril_vendor_request_to_string(mtk, 0));
|
||||
g_assert(!ril_vendor_event_to_string(mtk, 0));
|
||||
ril_vendor_unref(mtk);
|
||||
}
|
||||
|
||||
static const char *MTK_RESUME_REGISTRATION="MTK_RESUME_REGISTRATION";
|
||||
static const char *MTK_SET_CALL_INDICATION="MTK_SET_CALL_INDICATION";
|
||||
static const char *MTK_PS_NETWORK_STATE_CHANGED="MTK_PS_NETWORK_STATE_CHANGED";
|
||||
static const char *MTK_REGISTRATION_SUSPENDED="MTK_REGISTRATION_SUSPENDED";
|
||||
static const char *MTK_SET_ATTACH_APN="MTK_SET_ATTACH_APN";
|
||||
static const char *MTK_INCOMING_CALL_INDICATION="MTK_INCOMING_CALL_INDICATION";
|
||||
|
||||
static void test_mtk1(void)
|
||||
{
|
||||
const struct ril_vendor_driver *driver = ril_vendor_find_driver("mtk1");
|
||||
struct ril_slot_config config;
|
||||
struct ril_vendor *mtk1;
|
||||
GRilIoRequest* req;
|
||||
|
||||
g_assert(driver);
|
||||
memset(&config, 0, sizeof(config));
|
||||
mtk1 = ril_vendor_create(driver, NULL, NULL, &config);
|
||||
g_assert(mtk1);
|
||||
|
||||
g_assert(!g_strcmp0(ril_vendor_request_to_string(mtk1, 2050),
|
||||
MTK_RESUME_REGISTRATION));
|
||||
g_assert(!g_strcmp0(ril_vendor_request_to_string(mtk1, 2065),
|
||||
MTK_SET_CALL_INDICATION));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk1, 3012),
|
||||
MTK_PS_NETWORK_STATE_CHANGED));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk1, 3021),
|
||||
MTK_REGISTRATION_SUSPENDED));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk1, 3065),
|
||||
MTK_SET_ATTACH_APN));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk1, 3037),
|
||||
MTK_INCOMING_CALL_INDICATION));
|
||||
|
||||
/* mtk1 doesn't parse data calls */
|
||||
g_assert(!ril_vendor_data_call_parse(mtk1, NULL, 0, NULL));
|
||||
|
||||
/* Build RIL_REQUEST_SET_INITIAL_ATTACH_APN */
|
||||
req = ril_vendor_set_attach_apn_req(mtk1, "apn", "username",
|
||||
"password", RIL_AUTH_NONE, "IP");
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Build RIL_REQUEST_SETUP_DATA_CALL */
|
||||
req = ril_vendor_data_call_req(mtk1, 1, RIL_DATA_PROFILE_DEFAULT,
|
||||
"apn", "username", "password", RIL_AUTH_NONE, "IP");
|
||||
grilio_request_unref(req);
|
||||
|
||||
ril_vendor_unref(mtk1);
|
||||
}
|
||||
|
||||
static void test_mtk2(void)
|
||||
{
|
||||
static const guint8 noprot[] = {
|
||||
0x00, 0x00, 0x00, 0x00, /* status */
|
||||
0x00, 0x00, 0x00, 0x00, /* retry_time */
|
||||
0x00, 0x00, 0x00, 0x00, /* cid */
|
||||
0x02, 0x00, 0x00, 0x00, /* active */
|
||||
0x00, 0x05, 0x00, 0x00 /* mtu */
|
||||
};
|
||||
static const guint8 noifname[] = {
|
||||
0x00, 0x00, 0x00, 0x00, /* status */
|
||||
0x00, 0x00, 0x00, 0x00, /* retry_time */
|
||||
0x00, 0x00, 0x00, 0x00, /* cid */
|
||||
0x02, 0x00, 0x00, 0x00, /* active */
|
||||
0x00, 0x05, 0x00, 0x00, /* mtu */
|
||||
/* "IP" */
|
||||
0x02, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
static const guint8 noaddr[] = {
|
||||
0x00, 0x00, 0x00, 0x00, /* status */
|
||||
0x00, 0x00, 0x00, 0x00, /* retry_time */
|
||||
0x00, 0x00, 0x00, 0x00, /* cid */
|
||||
0x02, 0x00, 0x00, 0x00, /* active */
|
||||
0x00, 0x05, 0x00, 0x00, /* mtu */
|
||||
/* "IP" */
|
||||
0x02, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* "ccmni0" */
|
||||
0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x63, 0x00,
|
||||
0x6d, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x30, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
static const guint8 datacall[] = {
|
||||
0x00, 0x00, 0x00, 0x00, /* status */
|
||||
0x00, 0x00, 0x00, 0x00, /* retry_time */
|
||||
0x00, 0x00, 0x00, 0x00, /* cid */
|
||||
0x02, 0x00, 0x00, 0x00, /* active */
|
||||
0x00, 0x05, 0x00, 0x00, /* mtu */
|
||||
/* "IP" */
|
||||
0x02, 0x00, 0x00, 0x00, 0x49, 0x00, 0x50, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* "ccmni0" */
|
||||
0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x63, 0x00,
|
||||
0x6d, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x30, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* "10.236.123.155" */
|
||||
0x0e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x30, 0x00,
|
||||
0x2e, 0x00, 0x32, 0x00, 0x33, 0x00, 0x36, 0x00,
|
||||
0x2e, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00,
|
||||
0x2e, 0x00, 0x31, 0x00, 0x35, 0x00, 0x35, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* "217.118.66.243 217.118.66.244" */
|
||||
0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x31, 0x00,
|
||||
0x37, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x31, 0x00,
|
||||
0x38, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x36, 0x00,
|
||||
0x2e, 0x00, 0x32, 0x00, 0x34, 0x00, 0x33, 0x00,
|
||||
0x20, 0x00, 0x32, 0x00, 0x31, 0x00, 0x37, 0x00,
|
||||
0x2e, 0x00, 0x31, 0x00, 0x31, 0x00, 0x38, 0x00,
|
||||
0x2e, 0x00, 0x36, 0x00, 0x36, 0x00, 0x2e, 0x00,
|
||||
0x32, 0x00, 0x34, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||
/* "10.236.123.155" */
|
||||
0x0e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x30, 0x00,
|
||||
0x2e, 0x00, 0x32, 0x00, 0x33, 0x00, 0x36, 0x00,
|
||||
0x2e, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00,
|
||||
0x2e, 0x00, 0x31, 0x00, 0x35, 0x00, 0x35, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
/* whatever... */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const struct ril_vendor_driver *driver = ril_vendor_find_driver("mtk2");
|
||||
struct ril_slot_config config;
|
||||
struct ril_data_call call;
|
||||
struct ril_vendor *mtk2;
|
||||
GRilIoParser rilp;
|
||||
GRilIoRequest* req;
|
||||
|
||||
g_assert(driver);
|
||||
memset(&config, 0, sizeof(config));
|
||||
mtk2 = ril_vendor_create(driver, NULL, NULL, &config);
|
||||
g_assert(mtk2);
|
||||
|
||||
g_assert(!g_strcmp0(ril_vendor_request_to_string(mtk2, 2065),
|
||||
MTK_RESUME_REGISTRATION));
|
||||
g_assert(!g_strcmp0(ril_vendor_request_to_string(mtk2, 2086),
|
||||
MTK_SET_CALL_INDICATION));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk2, 3015),
|
||||
MTK_PS_NETWORK_STATE_CHANGED));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk2, 3024),
|
||||
MTK_REGISTRATION_SUSPENDED));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk2, 3073),
|
||||
MTK_SET_ATTACH_APN));
|
||||
g_assert(!g_strcmp0(ril_vendor_event_to_string(mtk2, 3042),
|
||||
MTK_INCOMING_CALL_INDICATION));
|
||||
|
||||
/* Build RIL_REQUEST_SET_INITIAL_ATTACH_APN */
|
||||
req = ril_vendor_set_attach_apn_req(mtk2, "apn", "username",
|
||||
"password", RIL_AUTH_NONE, "IP");
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Build RIL_REQUEST_SETUP_DATA_CALL */
|
||||
req = ril_vendor_data_call_req(mtk2, 1, RIL_DATA_PROFILE_DEFAULT,
|
||||
"apn", "username", "password", RIL_AUTH_NONE, "IP");
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Parse data call (version < 11) */
|
||||
memset(&call, 0, sizeof(call));
|
||||
memset(&rilp, 0, sizeof(rilp));
|
||||
g_assert(!ril_vendor_data_call_parse(mtk2, &call, 11, &rilp));
|
||||
|
||||
memset(&call, 0, sizeof(call));
|
||||
grilio_parser_init(&rilp, noprot, sizeof(noprot));
|
||||
g_assert(!ril_vendor_data_call_parse(mtk2, &call, 10, &rilp));
|
||||
|
||||
memset(&call, 0, sizeof(call));
|
||||
grilio_parser_init(&rilp, noifname, sizeof(noifname));
|
||||
g_assert(!ril_vendor_data_call_parse(mtk2, &call, 10, &rilp));
|
||||
|
||||
memset(&call, 0, sizeof(call));
|
||||
grilio_parser_init(&rilp, noaddr, sizeof(noaddr));
|
||||
g_assert(!ril_vendor_data_call_parse(mtk2, &call, 10, &rilp));
|
||||
g_free(call.ifname);
|
||||
|
||||
grilio_parser_init(&rilp, datacall, sizeof(datacall));
|
||||
g_assert(ril_vendor_data_call_parse(mtk2, &call, 10, &rilp));
|
||||
g_assert(call.active == RIL_DATA_CALL_ACTIVE);
|
||||
g_assert(call.mtu == 1280);
|
||||
g_assert(call.prot == OFONO_GPRS_PROTO_IP);
|
||||
g_assert(!g_strcmp0(call.ifname, "ccmni0"));
|
||||
g_assert(!g_strcmp0(call.dnses[0], "217.118.66.243"));
|
||||
g_assert(!g_strcmp0(call.dnses[1], "217.118.66.244"));
|
||||
g_assert(!call.dnses[2]);
|
||||
g_assert(!g_strcmp0(call.gateways[0], "10.236.123.155"));
|
||||
g_assert(!call.gateways[1]);
|
||||
g_assert(!g_strcmp0(call.addresses[0], "10.236.123.155"));
|
||||
g_assert(!call.addresses[1]);
|
||||
g_free(call.ifname);
|
||||
g_strfreev(call.dnses);
|
||||
g_strfreev(call.gateways);
|
||||
g_strfreev(call.addresses);
|
||||
|
||||
ril_vendor_unref(mtk2);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_vendor/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-ril_vendor",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("drivers"), test_drivers);
|
||||
g_test_add_func(TEST_("base"), test_base);
|
||||
g_test_add_func(TEST_("mtk"), test_mtk);
|
||||
g_test_add_func(TEST_("mtk1"), test_mtk1);
|
||||
g_test_add_func(TEST_("mtk2"), test_mtk2);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -6,17 +6,12 @@ License: GPLv2
|
||||
URL: https://github.com/sailfishos/ofono
|
||||
Source: %{name}-%{version}.tar.bz2
|
||||
|
||||
%define libgrilio_version 1.0.38
|
||||
%define libglibutil_version 1.0.30
|
||||
%define libmce_version 1.0.6
|
||||
%define libglibutil_version 1.0.49
|
||||
|
||||
Requires: dbus
|
||||
Requires: systemd
|
||||
Requires: ofono-configs
|
||||
Requires: libglibutil >= %{libglibutil_version}
|
||||
Requires: libgrilio >= %{libgrilio_version}
|
||||
Requires: libmce-glib >= %{libmce_version}
|
||||
Requires: mobile-broadband-provider-info
|
||||
Requires(preun): systemd
|
||||
Requires(post): systemd
|
||||
@@ -30,8 +25,6 @@ BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(libudev) >= 145
|
||||
BuildRequires: pkgconfig(libwspcodec) >= 2.0
|
||||
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
|
||||
BuildRequires: pkgconfig(libgrilio) >= %{libgrilio_version}
|
||||
BuildRequires: pkgconfig(libmce-glib) >= %{libmce_version}
|
||||
BuildRequires: pkgconfig(libdbuslogserver-dbus)
|
||||
BuildRequires: pkgconfig(libdbusaccess)
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
@@ -61,13 +54,6 @@ Obsoletes: ofono-test < 1.0
|
||||
%description tests
|
||||
Scripts for testing oFono and its functionality
|
||||
|
||||
%package configs-mer
|
||||
Summary: Package to provide default configs for ofono
|
||||
Provides: ofono-configs
|
||||
|
||||
%description configs-mer
|
||||
This package provides default configs for ofono
|
||||
|
||||
%package doc
|
||||
Summary: Documentation for %{name}
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
@@ -89,9 +75,9 @@ autoreconf --force --install
|
||||
--enable-sailfish-debuglog \
|
||||
--enable-sailfish-provision \
|
||||
--enable-sailfish-pushforwarder \
|
||||
--enable-sailfish-rilmodem \
|
||||
--enable-sailfish-access \
|
||||
--disable-add-remove-context \
|
||||
--disable-rilmodem \
|
||||
--disable-isimodem \
|
||||
--disable-qmimodem \
|
||||
--with-systemdunitdir=%{_unitdir}
|
||||
@@ -155,10 +141,6 @@ systemctl try-restart ofono.service ||:
|
||||
%defattr(-,root,root,-)
|
||||
%{_libdir}/%{name}/test/*
|
||||
|
||||
%files configs-mer
|
||||
%defattr(-,root,root,-)
|
||||
%config /etc/ofono/ril_subscription.conf
|
||||
|
||||
%files doc
|
||||
%defattr(-,root,root,-)
|
||||
%{_mandir}/man8/%{name}d.*
|
||||
|
||||
Reference in New Issue
Block a user