Compare commits

..

17 Commits

Author SHA1 Message Date
Slava Monich
24fd7e863c [unit] Added one more slot-manager test case 2022-01-10 21:10:26 +02:00
Slava Monich
3bdcd55ad8 Merge pull request #21 from monich/imsi-change
Fix re-evaluation of data slot after SIM change
2022-01-10 19:54:55 +02:00
Slava Monich
fb76fa7be1 [ofono] Fixed re-evaluation of data slot after SIM change. JB#56789
The way it was done, slot driver wasn't always notified about the
role change after IMSI update (e.g. when SIM gets hot-swapped or
enabled/disabled) which could result in mobile data remaining
disabled.
2022-01-10 19:16:41 +02:00
Slava Monich
25c11d6697 Updated upstream hash to point to 1.27 2022-01-10 00:12:23 +02:00
Slava Monich
0f789ddf25 Merge pull request #19 from sailfish-on-dontbeevil/branch-1.27
[ofono] Update baseline to 1.27. JB#42254
2022-01-10 00:07:34 +02:00
Slava Monich
cfae9cd095 include: Housekeeping 2022-01-10 00:01:23 +02:00
Marcel Holtmann
dca2747d5f Release 1.27 2022-01-08 08:39:08 +00:00
Antara Borwankar
b6df026722 xmm7modem: modified ofono.conf for coex agent
Added coex agent interface to ofono.conf
2022-01-08 08:39:08 +00:00
Denis Kenzior
aa1e36040d xmm7xxx: Various style cleanups 2022-01-08 08:39:08 +00:00
Antara Borwankar
227af51e10 xmm7modem: implemnetation of coexistence functionality
Added coex implementation in xmm7modem plugin
2022-01-08 08:39:08 +00:00
Pau Espin Pedrol
cbab683ac2 qmi: Fix Secondary DNS overwriting Primary DNS
inet_ntoa was called twice in a row and as a result both primay and
secondary DNS were pointing to same static buffer containing last
value (secondary DNS).

As a result, ofono always advertised the secondary DNS twice through
DBus ConnectionContext.GetProperties 'DomainNameServers'.

Related: https://osmocom.org/issues/3031
2022-01-08 08:39:08 +00:00
Antara Borwankar
8a42f7cf48 doc: Adding documetation for intel LTE coex
Added intel-lte-coex-api.txt which defines LTE coexistence
interface for intel modems.
2022-01-08 08:39:08 +00:00
Nandini Rebello
45b8b675ac test: Fix number of arguments check in change-pin
Fix the number of arguments checked in second case of change-pin.
2022-01-08 08:39:08 +00:00
Nandini Rebello
b977415db8 xmm7xxx: Adding case for SIM PIN locked state
Handling the case when SIM PIN is enabled for xmm7xxx modem.
2022-01-08 08:39:08 +00:00
Clement Viel
011377b505 sim800: add sim800 support 2022-01-08 08:39:08 +00:00
Clement Viel
7653e2b293 sim800: merge sim800 and sim900 documentation. 2022-01-08 08:39:08 +00:00
Slava Monich
0012a3e4f0 Updated upstream hash to point to 1.26 2022-01-08 04:50:14 +02:00
13 changed files with 1302 additions and 52 deletions

View File

@@ -1,3 +1,8 @@
ver 1.27:
Add support for handling SIMCom based SIM800 modems.
Add support for SIM lock state with xmm7xxx modems.
Add support for coexistence feature with xmm7xxx modems.
ver 1.26:
Fix issue with AT callback handler and GPRS.
Fix issue with handling EUTRAN SMS only states.

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.26)
AC_INIT(ofono, 1.27)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)

View File

@@ -0,0 +1,137 @@
LTE Coexistence hierarchy
=========================
Service org.ofono
Interface org.ofono.intel.LteCoexistence
Object path [variable prefix]/{modem0,modem1,...}
Methods dict GetProperties()
Returns all coexistence configuration properties.
void SetProperty(string property, variant value)
Changes the value of the specified property. Only
properties that are listed as Read-write are changeable.
On success a PropertyChanged signal will be emitted.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.Failed
void RegisterAgent(object path)
Registers an agent which will be called whenever the
modem initiates LTE Coexistence information.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.InvalidFormat
[service].Error.Failed
void UnregisterAgent(object path)
Unregisters an agent.
Possible Errors: [service].Error.InvalidArguments
[service].Error.Failed
a(a{sv}) GetPlmnHistory()
Requests for LTE Plmn history list stored in NVM to
retrieve geo location history like MobileNetworkCode,
MobileCountryCode, LteBandsFDD, LteBandsTDD,
ChannelBandwidth.
Refer to the sections below for which property types
are available, their valid value ranges and
applicability to different cell types.
Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given
property.
Properties string Band [readwrite]
Frequency band in which the modem is operating when
using "lte" mode.
boolean BTActive [readwrite]
Contains whether BT Coex is activated or not.
boolean WLANActive [readwrite]
Contains whether WLAN Coex is activated or not.
string WLANBandwidth [readwrite]
Contains the frequency WLAN Coex is activated on, when
"CoexWLANActive" is active.
The possible values are:
- "20MHz"
- "40MHz"
- "80MHz"
LTECoexistenceAgent Hierarchy [experimental]
=============================
Service unique name
Interface org.ofono.intel.LteCoexistenceAgent
Object path freely definable
Methods void ReceiveBluetoothNotification(array{byte} notification,
dict info) [noreply]
Requests the agent to process Bluetooth related LTE
Coexistence information. The dictionary info contains
vector table with modem recommended Safe Tx/Rx band and
range information.The properties involved are
'SafeTxMin', 'SafeRxMin', 'SafeTxMax', 'SafeRxMax' and
'SafeVector'.
Possible Errors: None
void ReceiveWiFiNotification(array{byte} notification,
dict info) [noreply]
Requests the agent to process WiFi related LTE
Coexistence information. The dictionary info contains
vector table with modem recommended SafeTx/Rx band and
range information. The properties involved are
'SafeTxMin', 'SafeRxMin', 'SafeTxMax', 'SafeRxMax' and
'SafeVector'.
Possible Errors: None
void Release() [noreply]
Agent is being released, possibly because of oFono
terminating, Coex interface is being torn down or modem
off. No UnregisterAgent call is needed.
LTE Plmn history params
=======================
uint16 MobileNetworkCode [readonly, optional]
Contains the MNC of the cell.
uint16 MobileCountryCode [readonly, optional]
Contains the MCC of the cell.
uint32 LteBandsFDD [readonly, optional]
Contains the Lte FDD band. Valid range of values is 1 to 32 as per
3GPP 36.101 Section 5.5.
uint32 LteBandsTDD [readonly, optional]
Contains the Lte TDD band. Valid range of values is 33 to 64 as per
3GPP 36.101 Section 5.5.
byte ChannelBandwidth [readonly, optional]
Contains the Channel bandwidth. Valid range of values is 0 to 6 as per
3GPP 36.101 Section 5.6.

View File

@@ -10,3 +10,13 @@ On the i-Tetra tracking device, the SIM900 is accessed
via N_GSM mux device. We use ofono as SMS message
service and incoming voice calls service, so we
use /dev/gsmtty1 provided by N_GSM mux.
SIM800 modem usage
==================
When using sim800 modem, the udev rule is the same as the
sim900 rule :
KERNEL=="ttyS3", ENV{OFONO_DRIVER}="sim900"
Because the SIM800 and SIM900 code are the merged into one driver.

View File

@@ -88,6 +88,7 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
char* straddr;
char* apn;
const char *dns[3] = { NULL, NULL, NULL };
char dns_buf[2][INET_ADDRSTRLEN];
DBG("");
@@ -131,14 +132,14 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
if (qmi_result_get_uint32(result,
QMI_WDS_RESULT_PRIMARY_DNS, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
dns[0] = inet_ntoa(addr);
dns[0] = inet_ntop(AF_INET, &addr, dns_buf[0], sizeof(dns_buf[0]));
DBG("Primary DNS: %s", dns[0]);
}
if (qmi_result_get_uint32(result,
QMI_WDS_RESULT_SECONDARY_DNS, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
dns[1] = inet_ntoa(addr);
dns[1] = inet_ntop(AF_INET, &addr, dns_buf[1], sizeof(dns_buf[1]));
DBG("Secondary DNS: %s", dns[1]);
}

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 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
@@ -32,7 +32,7 @@ extern "C" {
struct ofono_modem;
struct ofono_netreg;
enum ofono_netreg_status {
enum ofono_netreg_status { /* Since mer/1.24+git2 */
OFONO_NETREG_STATUS_NONE = -1,
/* 27.007 Section 7.2 <stat> */
OFONO_NETREG_STATUS_NOT_REGISTERED = 0,
@@ -41,9 +41,10 @@ enum ofono_netreg_status {
OFONO_NETREG_STATUS_DENIED = 3,
OFONO_NETREG_STATUS_UNKNOWN = 4,
OFONO_NETREG_STATUS_ROAMING = 5,
OFONO_NETREG_STATUS_REGISTERED_SMS_EUTRAN = 6,
OFONO_NETREG_STATUS_ROAMING_SMS_EUTRAN = 7,
}; /* Since mer/1.24+git2 */
/* Since mer/1.26+git1 */
OFONO_NETREG_STATUS_REGISTERED_SMS_EUTRAN = 6,
OFONO_NETREG_STATUS_ROAMING_SMS_EUTRAN = 7
};
/* 27.007 Section 7.3 <stat> */
enum ofono_operator_status {

View File

@@ -24,6 +24,7 @@
#endif
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <gatchat.h>
@@ -60,13 +61,66 @@ static char *dlc_prefixes[NUM_DLC] = { "Voice: ", "Net: ", "SMS: ",
static const char *none_prefix[] = { NULL };
enum type {
SIMCOM_UNKNOWN,
SIM800,
SIM900,
};
struct sim900_data {
GIOChannel *device;
GAtMux *mux;
GAtChat * dlcs[NUM_DLC];
guint frame_size;
enum type modem_type;
};
static void mux_ready_notify(GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
struct sim900_data *data = ofono_modem_get_data(modem);
struct ofono_gprs *gprs = NULL;
struct ofono_gprs_context *gc;
ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
data->dlcs[SMS_DLC]);
gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]);
if (gprs == NULL)
return;
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM,
"atmodem", data->dlcs[GPRS_DLC]);
if (gc)
ofono_gprs_add_context(gprs, gc);
}
static void check_model(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
GAtResultIter iter;
char const *model;
struct sim900_data *data = ofono_modem_get_data(modem);
DBG("");
g_at_result_iter_init(&iter, result);
while (g_at_result_iter_next(&iter, NULL)) {
if (!g_at_result_iter_next_unquoted_string(&iter, &model))
continue;
DBG("setting type %s", model);
if (strstr(model, "SIM800"))
data->modem_type = SIM800;
else if (strstr(model, "SIM900"))
data->modem_type = SIM800;
else
data->modem_type = SIMCOM_UNKNOWN;
}
}
static int sim900_probe(struct ofono_modem *modem)
{
struct sim900_data *data;
@@ -233,6 +287,14 @@ static void setup_internal_mux(struct ofono_modem *modem)
}
}
if (data->modem_type == SIM800) {
for (i = 0; i<NUM_DLC; i++) {
g_at_chat_register(data->dlcs[i], "SMS Ready",
mux_ready_notify, FALSE,
modem, NULL);
}
}
ofono_modem_set_powered(modem, TRUE);
return;
@@ -294,6 +356,8 @@ static int sim900_enable(struct ofono_modem *modem)
return -EINVAL;
g_at_chat_send(data->dlcs[SETUP_DLC], "ATE0", NULL, NULL, NULL, NULL);
g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CGMM", NULL,
check_model, modem, NULL);
/* For obtain correct sms service number */
g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CSCS=\"GSM\"", NULL,
@@ -353,18 +417,24 @@ static void sim900_post_sim(struct ofono_modem *modem)
DBG("%p", modem);
ofono_phonebook_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
if (data->modem_type == SIM900) {
ofono_phonebook_create(modem, 0, "atmodem",
data->dlcs[VOICE_DLC]);
ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
data->dlcs[SMS_DLC]);
gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]);
if (gprs == NULL)
return;
gprs = ofono_gprs_create(modem, 0, "atmodem",
data->dlcs[GPRS_DLC]);
if (gprs == NULL)
return;
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM_SIM900,
"atmodem", data->dlcs[GPRS_DLC]);
if (gc)
ofono_gprs_add_context(gprs, gc);
gc = ofono_gprs_context_create(modem,
OFONO_VENDOR_SIMCOM_SIM900,
"atmodem",
data->dlcs[GPRS_DLC]);
if (gc)
ofono_gprs_add_context(gprs, gc);
}
}
static void sim900_post_online(struct ofono_modem *modem)

View File

@@ -57,16 +57,904 @@
#include <drivers/atmodem/atutil.h>
#include <drivers/atmodem/vendor.h>
#include "ofono.h"
#include "gdbus.h"
#define OFONO_COEX_INTERFACE OFONO_SERVICE ".intel.LteCoexistence"
#define OFONO_COEX_AGENT_INTERFACE OFONO_SERVICE ".intel.LteCoexistenceAgent"
#define NET_BAND_LTE_INVALID 0
#define NET_BAND_LTE_1 101
#define NET_BAND_LTE_43 143
#define BAND_LEN 20
#define MAX_BT_SAFE_VECTOR 15
#define MAX_WL_SAFE_VECTOR 13
static const char *none_prefix[] = { NULL };
static const char *xsimstate_prefix[] = { "+XSIMSTATE:", NULL };
static const char *xnvmplmn_prefix[] = { "+XNVMPLMN:", NULL };
struct bt_coex_info {
int safe_tx_min;
int safe_tx_max;
int safe_rx_min;
int safe_rx_max;
int safe_vector[MAX_BT_SAFE_VECTOR];
int num_safe_vector;
};
struct wl_coex_info {
int safe_tx_min;
int safe_tx_max;
int safe_rx_min;
int safe_rx_max;
int safe_vector[MAX_BT_SAFE_VECTOR];
int num_safe_vector;
};
struct coex_agent {
char *path;
char *bus;
guint disconnect_watch;
ofono_bool_t remove_on_terminate;
ofono_destroy_func removed_cb;
void *removed_data;
DBusMessage *msg;
};
struct xmm7xxx_data {
GAtChat *chat; /* AT chat */
struct ofono_sim *sim;
ofono_bool_t have_sim;
ofono_bool_t sms_phonebook_added;
unsigned int netreg_watch;
};
/* Coex Implementation */
enum wlan_bw {
WLAN_BW_UNSUPPORTED = -1,
WLAN_BW_20MHZ = 0,
WLAN_BW_40MHZ = 1,
WLAN_BW_80MHZ = 2,
};
struct plmn_hist {
unsigned short mnc;
unsigned short mcc;
unsigned long tdd;
unsigned long fdd;
unsigned char bw;
};
struct xmm7xxx_coex {
GAtChat *chat;
struct ofono_modem *modem;
DBusMessage *pending;
ofono_bool_t bt_active;
ofono_bool_t wlan_active;
enum wlan_bw wlan_bw;
char *lte_band;
ofono_bool_t pending_bt_active;
ofono_bool_t pending_wlan_active;
enum wlan_bw pending_wlan_bw;
struct coex_agent *session_agent;
};
static ofono_bool_t coex_agent_matches(struct coex_agent *agent,
const char *path, const char *sender)
{
return !strcmp(agent->path, path) && !strcmp(agent->bus, sender);
}
static void coex_agent_set_removed_notify(struct coex_agent *agent,
ofono_destroy_func destroy,
void *user_data)
{
agent->removed_cb = destroy;
agent->removed_data = user_data;
}
static void coex_agent_send_noreply(struct coex_agent *agent,
const char *method)
{
DBusConnection *conn = ofono_dbus_get_connection();
DBusMessage *message;
message = dbus_message_new_method_call(agent->bus, agent->path,
OFONO_COEX_INTERFACE,
method);
if (message == NULL)
return;
dbus_message_set_no_reply(message, TRUE);
g_dbus_send_message(conn, message);
}
static void coex_agent_send_release(struct coex_agent *agent)
{
coex_agent_send_noreply(agent, "Release");
}
static void coex_agent_free(struct coex_agent *agent)
{
DBusConnection *conn = ofono_dbus_get_connection();
if (agent->disconnect_watch) {
coex_agent_send_release(agent);
g_dbus_remove_watch(conn, agent->disconnect_watch);
agent->disconnect_watch = 0;
}
if (agent->removed_cb)
agent->removed_cb(agent->removed_data);
g_free(agent->path);
g_free(agent->bus);
g_free(agent);
}
static void coex_agent_disconnect_cb(DBusConnection *conn, void *user_data)
{
struct coex_agent *agent = user_data;
ofono_debug("Agent exited without calling Unregister");
agent->disconnect_watch = 0;
coex_agent_free(agent);
}
static struct coex_agent *coex_agent_new(const char *path, const char *sender,
ofono_bool_t remove_on_terminate)
{
struct coex_agent *agent = g_try_new0(struct coex_agent, 1);
DBusConnection *conn = ofono_dbus_get_connection();
DBG("");
if (agent == NULL)
return NULL;
agent->path = g_strdup(path);
agent->bus = g_strdup(sender);
agent->remove_on_terminate = remove_on_terminate;
agent->disconnect_watch = g_dbus_add_disconnect_watch(conn, sender,
coex_agent_disconnect_cb,
agent, NULL);
return agent;
}
static int coex_agent_coex_wlan_notify(struct coex_agent *agent,
const struct wl_coex_info wlan_info)
{
DBusConnection *conn = ofono_dbus_get_connection();
DBusMessageIter wl_args, wl_dict, wl_array;
const dbus_int32_t *pwl_array = wlan_info.safe_vector;
dbus_int32_t value;
agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
OFONO_COEX_AGENT_INTERFACE,
"ReceiveWiFiNotification");
if (agent->msg == NULL)
return -ENOMEM;
dbus_message_iter_init_append(agent->msg, &wl_args);
dbus_message_iter_open_container(&wl_args, DBUS_TYPE_ARRAY,
DBUS_TYPE_INT32_AS_STRING, &wl_array);
dbus_message_iter_append_fixed_array(&wl_array, DBUS_TYPE_INT32,
&pwl_array, MAX_WL_SAFE_VECTOR);
dbus_message_iter_close_container(&wl_args, &wl_array);
dbus_message_iter_open_container(&wl_args, DBUS_TYPE_ARRAY,
"{sv}", &wl_dict);
value = wlan_info.safe_tx_min;
ofono_dbus_dict_append(&wl_dict, "SafeTxMin", DBUS_TYPE_UINT32, &value);
value = wlan_info.safe_tx_max;
ofono_dbus_dict_append(&wl_dict, "SafeTxMax", DBUS_TYPE_UINT32, &value);
value = wlan_info.safe_rx_min;
ofono_dbus_dict_append(&wl_dict, "SafeRxMin", DBUS_TYPE_UINT32, &value);
value = wlan_info.safe_rx_max;
ofono_dbus_dict_append(&wl_dict, "SafeRxMax", DBUS_TYPE_UINT32, &value);
value = wlan_info.num_safe_vector;
ofono_dbus_dict_append(&wl_dict, "NumSafeVector",
DBUS_TYPE_UINT32, &value);
dbus_message_iter_close_container(&wl_args, &wl_dict);
dbus_message_set_no_reply(agent->msg, TRUE);
if (dbus_connection_send(conn, agent->msg, NULL) == FALSE)
return -EIO;
dbus_message_unref(agent->msg);
return 0;
}
static int coex_agent_coex_bt_notify(struct coex_agent *agent,
const struct bt_coex_info bt_info)
{
DBusConnection *conn = ofono_dbus_get_connection();
DBusMessageIter bt_args, bt_dict, bt_array;
const dbus_int32_t *pbt_array = bt_info.safe_vector;
int len = MAX_BT_SAFE_VECTOR;
dbus_int32_t value;
agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
OFONO_COEX_AGENT_INTERFACE,
"ReceiveBTNotification");
if (agent->msg == NULL)
return -ENOMEM;
pbt_array = bt_info.safe_vector;
dbus_message_iter_init_append(agent->msg, &bt_args);
dbus_message_iter_open_container(&bt_args, DBUS_TYPE_ARRAY,
DBUS_TYPE_INT32_AS_STRING, &bt_array);
dbus_message_iter_append_fixed_array(&bt_array, DBUS_TYPE_INT32,
&pbt_array, len);
dbus_message_iter_close_container(&bt_args, &bt_array);
dbus_message_iter_open_container(&bt_args,
DBUS_TYPE_ARRAY, "{sv}", &bt_dict);
value = bt_info.safe_tx_min;
DBG("value = %d", value);
ofono_dbus_dict_append(&bt_dict, "SafeTxMin", DBUS_TYPE_UINT32, &value);
value = bt_info.safe_tx_max;
DBG("value = %d", value);
ofono_dbus_dict_append(&bt_dict, "SafeTxMax", DBUS_TYPE_UINT32, &value);
value = bt_info.safe_rx_min;
DBG("value = %d", value);
ofono_dbus_dict_append(&bt_dict, "SafeRxMin", DBUS_TYPE_UINT32, &value);
value = bt_info.safe_rx_max;
DBG("value = %d", value);
ofono_dbus_dict_append(&bt_dict, "SafeRxMax", DBUS_TYPE_UINT32, &value);
value = bt_info.num_safe_vector;
DBG("value = %d", value);
ofono_dbus_dict_append(&bt_dict, "NumSafeVector",
DBUS_TYPE_UINT32, &value);
dbus_message_iter_close_container(&bt_args, &bt_dict);
if (dbus_connection_send(conn, agent->msg, NULL) == FALSE)
return -EIO;
dbus_message_unref(agent->msg);
return 0;
}
static gboolean coex_wlan_bw_from_string(const char *str,
enum wlan_bw *band)
{
if (g_str_equal(str, "20")) {
*band = WLAN_BW_20MHZ;
return TRUE;
} else if (g_str_equal(str, "40")) {
*band = WLAN_BW_40MHZ;
return TRUE;
} else if (g_str_equal(str, "80")) {
*band = WLAN_BW_80MHZ;
return TRUE;
} else
*band = WLAN_BW_UNSUPPORTED;
return FALSE;
}
static const char *wlan_bw_to_string(int band)
{
switch (band) {
case WLAN_BW_20MHZ:
return "20MHz";
case WLAN_BW_40MHZ:
return "40MHz";
case WLAN_BW_80MHZ:
return "80MHz";
case WLAN_BW_UNSUPPORTED:
return "UnSupported";
}
return "";
}
static void xmm_get_band_string(int lte_band, char *band)
{
int band_lte;
band_lte = lte_band - NET_BAND_LTE_1 + 1;
if (lte_band >= NET_BAND_LTE_1 && lte_band <= NET_BAND_LTE_43)
sprintf(band, "BAND_LTE_%d", band_lte);
else
sprintf(band, "INVALID");
}
static DBusMessage *coex_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct xmm7xxx_coex *coex = data;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter dict;
dbus_bool_t value;
const char *band = NULL;
reply = dbus_message_new_method_return(msg);
if (reply == NULL)
return NULL;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
OFONO_PROPERTIES_ARRAY_SIGNATURE,
&dict);
value = coex->bt_active;
ofono_dbus_dict_append(&dict, "BTActive",
DBUS_TYPE_BOOLEAN, &value);
value = coex->wlan_active;
ofono_dbus_dict_append(&dict, "WLANActive",
DBUS_TYPE_BOOLEAN, &value);
band = wlan_bw_to_string(coex->wlan_bw);
ofono_dbus_dict_append(&dict, "WLANBandwidth",
DBUS_TYPE_STRING, &band);
band = coex->lte_band;
ofono_dbus_dict_append(&dict, "Band", DBUS_TYPE_STRING, &band);
dbus_message_iter_close_container(&iter, &dict);
return reply;
}
static void coex_set_params_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct xmm7xxx_coex *coex = user_data;
DBusMessage *reply;
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = ofono_modem_get_path(coex->modem);
DBG("ok %d", ok);
if (!ok) {
coex->pending_bt_active = coex->bt_active;
coex->pending_wlan_active = coex->wlan_active;
coex->pending_wlan_bw = coex->wlan_bw;
reply = __ofono_error_failed(coex->pending);
__ofono_dbus_pending_reply(&coex->pending, reply);
return;
}
reply = dbus_message_new_method_return(coex->pending);
__ofono_dbus_pending_reply(&coex->pending, reply);
if (coex->bt_active != coex->pending_bt_active) {
coex->bt_active = coex->pending_bt_active;
ofono_dbus_signal_property_changed(conn, path,
OFONO_COEX_INTERFACE, "BTActive",
DBUS_TYPE_BOOLEAN, &coex->bt_active);
}
if (coex->wlan_active != coex->pending_wlan_active) {
coex->wlan_active = coex->pending_wlan_active;
ofono_dbus_signal_property_changed(conn, path,
OFONO_COEX_INTERFACE, "WLANActive",
DBUS_TYPE_BOOLEAN, &coex->wlan_active);
}
if (coex->wlan_bw != coex->pending_wlan_bw) {
const char *str_band = wlan_bw_to_string(coex->wlan_bw);
coex->wlan_bw = coex->pending_wlan_bw;
ofono_dbus_signal_property_changed(conn, path,
OFONO_COEX_INTERFACE, "WLANBandwidth",
DBUS_TYPE_STRING, &str_band);
}
}
static void coex_set_params(struct xmm7xxx_coex *coex, ofono_bool_t bt_active,
ofono_bool_t wlan_active, int wlan_bw)
{
char buf[64];
DBusMessage *reply;
DBG("");
sprintf(buf, "AT+XNRTCWS=65535,%u,%u,%u", (int)wlan_active,
wlan_bw, bt_active);
if (g_at_chat_send(coex->chat, buf, none_prefix,
coex_set_params_cb, coex, NULL) > 0)
return;
coex->pending_bt_active = coex->bt_active;
coex->pending_wlan_active = coex->wlan_active;
coex->pending_wlan_bw = coex->wlan_bw;
reply = __ofono_error_failed(coex->pending);
__ofono_dbus_pending_reply(&coex->pending, reply);
}
static DBusMessage *coex_set_property(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct xmm7xxx_coex *coex = data;
DBusMessageIter iter;
DBusMessageIter var;
const char *property;
dbus_bool_t value;
if (coex->pending)
return __ofono_error_busy(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &property);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
return __ofono_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &var);
if (!strcmp(property, "BTActive")) {
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &value);
if (coex->bt_active == (ofono_bool_t) value)
return dbus_message_new_method_return(msg);
coex->pending_bt_active = value;
coex->pending = dbus_message_ref(msg);
coex_set_params(coex, value, coex->wlan_active, coex->wlan_bw);
return NULL;
} else if (!strcmp(property, "WLANActive")) {
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &value);
if (coex->wlan_active == (ofono_bool_t) value)
return dbus_message_new_method_return(msg);
coex->pending_wlan_active = value;
coex->pending = dbus_message_ref(msg);
coex_set_params(coex, coex->bt_active, value, coex->wlan_bw);
return NULL;
} else if (g_strcmp0(property, "WLANBandwidth") == 0) {
const char *value;
enum wlan_bw band;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &value);
if (coex_wlan_bw_from_string(value, &band) == FALSE)
return __ofono_error_invalid_args(msg);
if (coex->wlan_bw == band)
return dbus_message_new_method_return(msg);
coex->pending_wlan_bw = band;
coex->pending = dbus_message_ref(msg);
coex_set_params(coex, coex->bt_active, coex->wlan_active, band);
return NULL;
} else {
return __ofono_error_invalid_args(msg);
}
return dbus_message_new_method_return(msg);
}
static void coex_default_agent_notify(gpointer user_data)
{
struct xmm7xxx_coex *coex = user_data;
g_at_chat_send(coex->chat, "AT+XNRTCWS=0", none_prefix,
NULL, NULL, NULL);
coex->session_agent = NULL;
}
static DBusMessage *coex_register_agent(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct xmm7xxx_coex *coex = data;
const char *agent_path;
if (coex->session_agent) {
DBG("Coexistence agent already registered");
return __ofono_error_busy(msg);
}
if (dbus_message_get_args(msg, NULL,
DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
coex->session_agent = coex_agent_new(agent_path,
dbus_message_get_sender(msg),
FALSE);
if (coex->session_agent == NULL)
return __ofono_error_failed(msg);
coex_agent_set_removed_notify(coex->session_agent,
coex_default_agent_notify, coex);
return dbus_message_new_method_return(msg);
}
static DBusMessage *coex_unregister_agent(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct xmm7xxx_coex *coex = data;
const char *agent_path;
const char *agent_bus = dbus_message_get_sender(msg);
if (dbus_message_get_args(msg, NULL,
DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (coex->session_agent == NULL)
return __ofono_error_failed(msg);
if (!coex_agent_matches(coex->session_agent, agent_path, agent_bus))
return __ofono_error_failed(msg);
coex_agent_send_release(coex->session_agent);
coex_agent_free(coex->session_agent);
g_at_chat_send(coex->chat, "AT+XNRTCWS=0", none_prefix,
NULL, NULL, NULL);
return dbus_message_new_method_return(msg);
}
static void append_plmn_properties(struct plmn_hist *list,
DBusMessageIter *dict)
{
ofono_dbus_dict_append(dict, "MobileCountryCode",
DBUS_TYPE_UINT16, &list->mcc);
ofono_dbus_dict_append(dict, "MobileNetworkCode",
DBUS_TYPE_UINT16, &list->mnc);
ofono_dbus_dict_append(dict, "LteBandsFDD",
DBUS_TYPE_UINT32, &list->fdd);
ofono_dbus_dict_append(dict, "LteBandsTDD",
DBUS_TYPE_UINT32, &list->tdd);
ofono_dbus_dict_append(dict, "ChannelBandwidth",
DBUS_TYPE_UINT32, &list->bw);
}
static void append_plmn_history_struct_list(struct plmn_hist *list,
DBusMessageIter *arr)
{
DBusMessageIter iter;
DBusMessageIter dict;
dbus_message_iter_open_container(arr, DBUS_TYPE_STRUCT, NULL, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
OFONO_PROPERTIES_ARRAY_SIGNATURE,
&dict);
append_plmn_properties(list, &dict);
dbus_message_iter_close_container(&iter, &dict);
dbus_message_iter_close_container(arr, &iter);
}
static void coex_get_plmn_history_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct xmm7xxx_coex *coex = user_data;
struct plmn_hist *list = NULL;
GAtResultIter iter;
int list_size = 0, count;
DBusMessage *reply;
DBusMessageIter itr, arr;
int value;
DBG("ok %d", ok);
if (!ok) {
__ofono_dbus_pending_reply(&coex->pending,
__ofono_error_failed(coex->pending));
return;
}
g_at_result_iter_init(&iter, result);
while (g_at_result_iter_next(&iter, "+XNVMPLMN:")) {
if (!list_size)
list = g_new0(struct plmn_hist, ++list_size);
else
list = g_renew(struct plmn_hist, list, ++list_size);
g_at_result_iter_next_number(&iter, &value);
list[list_size - 1].mcc = value;
g_at_result_iter_next_number(&iter, &value);
list[list_size - 1].mnc = value;
g_at_result_iter_next_number(&iter, &value);
list[list_size - 1].fdd = value;
g_at_result_iter_next_number(&iter, &value);
list[list_size - 1].tdd = value;
g_at_result_iter_next_number(&iter, &value);
list[list_size - 1].bw = value;
DBG("list_size = %d", list_size);
}
reply = dbus_message_new_method_return(coex->pending);
dbus_message_iter_init_append(reply, &itr);
dbus_message_iter_open_container(&itr, DBUS_TYPE_ARRAY,
DBUS_STRUCT_BEGIN_CHAR_AS_STRING
DBUS_TYPE_ARRAY_AS_STRING
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
DBUS_STRUCT_END_CHAR_AS_STRING,
&arr);
for (count = 0; count < list_size; count++)
append_plmn_history_struct_list(list, &arr);
dbus_message_iter_close_container(&itr, &arr);
reply = dbus_message_new_method_return(coex->pending);
__ofono_dbus_pending_reply(&coex->pending, reply);
g_free(list);
}
static DBusMessage *coex_get_plmn_history(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct xmm7xxx_coex *coex = data;
if (coex->pending)
return __ofono_error_busy(msg);
if (!g_at_chat_send(coex->chat, "AT+XNVMPLMN=2,2", xnvmplmn_prefix,
coex_get_plmn_history_cb, coex, NULL))
return __ofono_error_failed(msg);
coex->pending = dbus_message_ref(msg);
return NULL;
}
static const GDBusMethodTable coex_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
coex_get_properties) },
{ GDBUS_METHOD("SetProperty",
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
NULL, coex_set_property) },
{ GDBUS_METHOD("RegisterAgent",
GDBUS_ARGS({ "path", "o" }), NULL,
coex_register_agent) },
{ GDBUS_METHOD("UnregisterAgent",
GDBUS_ARGS({ "path", "o" }), NULL,
coex_unregister_agent) },
{ GDBUS_ASYNC_METHOD("GetPlmnHistory",
NULL, GDBUS_ARGS({ "plmnhistory", "a(a{sv})" }),
coex_get_plmn_history) },
{ }
};
static const GDBusSignalTable coex_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ }
};
static void xmm_coex_w_notify(GAtResult *result, gpointer user_data)
{
struct xmm7xxx_coex *coex = user_data;
GAtResultIter iter;
int count;
struct wl_coex_info wlan;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XNRTCWSW:"))
return;
g_at_result_iter_next_number(&iter, &wlan.safe_rx_min);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_next_number(&iter, &wlan.safe_rx_max);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_next_number(&iter, &wlan.safe_tx_min);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_next_number(&iter, &wlan.safe_tx_max);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_next_number(&iter, &wlan.num_safe_vector);
for (count = 0; count < wlan.num_safe_vector; count++)
g_at_result_iter_next_number(&iter, &wlan.safe_vector[count]);
DBG("WLAN notification");
if (coex->session_agent)
coex_agent_coex_wlan_notify(coex->session_agent, wlan);
}
static void xmm_coex_b_notify(GAtResult *result, gpointer user_data)
{
struct xmm7xxx_coex *coex = user_data;
GAtResultIter iter;
struct bt_coex_info bt;
int count;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XNRTCWSB:"))
return;
g_at_result_iter_next_number(&iter, &bt.safe_rx_min);
g_at_result_iter_next_number(&iter, &bt.safe_rx_max);
g_at_result_iter_next_number(&iter, &bt.safe_tx_min);
g_at_result_iter_next_number(&iter, &bt.safe_tx_max);
g_at_result_iter_next_number(&iter, &bt.num_safe_vector);
for (count = 0; count < bt.num_safe_vector; count++)
g_at_result_iter_next_number(&iter, &bt.safe_vector[count]);
DBG("BT notification");
if (coex->session_agent)
coex_agent_coex_bt_notify(coex->session_agent, bt);
}
static void xmm_lte_band_notify(GAtResult *result, gpointer user_data)
{
struct xmm7xxx_coex *coex = user_data;
GAtResultIter iter;
int lte_band;
char band[BAND_LEN];
const char *path = ofono_modem_get_path(coex->modem);
DBusConnection *conn = ofono_dbus_get_connection();
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XCCINFO:"))
return;
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
if (!g_at_result_iter_next_number(&iter, &lte_band))
return;
xmm_get_band_string(lte_band, band);
DBG("band %s", band);
if (!strcmp(band, coex->lte_band))
return;
g_free(coex->lte_band);
coex->lte_band = g_strdup(band);
if (coex->lte_band == NULL)
return;
ofono_dbus_signal_property_changed(conn, path,
OFONO_COEX_INTERFACE,
"Band", DBUS_TYPE_STRING, &coex->lte_band);
}
static void coex_cleanup(void *data)
{
struct xmm7xxx_coex *coex = data;
if (coex->pending)
__ofono_dbus_pending_reply(&coex->pending,
__ofono_error_canceled(coex->pending));
if (coex->session_agent) {
coex_agent_free(coex->session_agent);
g_at_chat_send(coex->chat, "AT+XNRTCWS=0", none_prefix,
NULL, NULL, NULL);
}
g_free(coex->lte_band);
g_free(coex);
}
static int xmm_coex_enable(struct ofono_modem *modem, void *data)
{
struct xmm7xxx_coex *coex = g_new0(struct xmm7xxx_coex, 1);
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = ofono_modem_get_path(modem);
DBG("coex enable");
coex->chat = data;
coex->modem = modem;
coex->bt_active = 0;
coex->wlan_active = 0;
coex->wlan_bw = WLAN_BW_20MHZ;
coex->lte_band = g_strdup("INVALID");
coex->session_agent = NULL;
if (!g_at_chat_send(coex->chat, "AT+XCCINFO=1", none_prefix,
NULL, NULL, NULL))
goto out;
if (!g_at_chat_send(coex->chat, "AT+XNRTCWS=7", none_prefix,
NULL, NULL, NULL))
goto out;
if (!g_dbus_register_interface(conn, path, OFONO_COEX_INTERFACE,
coex_methods,
coex_signals,
NULL, coex, coex_cleanup)) {
ofono_error("Could not register %s interface under %s",
OFONO_COEX_INTERFACE, path);
goto out;
}
ofono_modem_add_interface(modem, OFONO_COEX_INTERFACE);
g_at_chat_register(coex->chat, "+XNRTCWSW:", xmm_coex_w_notify,
FALSE, coex, NULL);
g_at_chat_register(coex->chat, "+XNRTCWSB:", xmm_coex_b_notify,
FALSE, coex, NULL);
g_at_chat_register(coex->chat, "+XCCINFO:", xmm_lte_band_notify,
FALSE, coex, NULL);
return 0;
out:
g_free(coex->lte_band);
g_free(coex);
return -EIO;
}
/* Coex Implementation Ends*/
static void xmm7xxx_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
@@ -129,6 +1017,12 @@ static void switch_sim_state_status(struct ofono_modem *modem, int status)
data->sms_phonebook_added = FALSE;
}
break;
case 1: /* SIM inserted, PIN verification needed */
if (data->have_sim == FALSE) {
ofono_sim_inserted_notify(data->sim, TRUE);
data->have_sim = TRUE;
}
break;
case 2: /* SIM inserted, PIN verification not needed - READY */
case 3: /* SIM inserted, PIN verified - READY */
case 7: /* SIM inserted, SMS and phonebook - READY */
@@ -236,6 +1130,29 @@ static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
xsimstate_query_cb, modem, NULL);
}
static void netreg_watch(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond,
void *data)
{
struct ofono_modem *modem = data;
struct xmm7xxx_data *modem_data = ofono_modem_get_data(modem);
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = ofono_modem_get_path(modem);
if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
if (g_dbus_unregister_interface(conn, path,
OFONO_COEX_INTERFACE))
ofono_modem_remove_interface(modem,
OFONO_COEX_INTERFACE);
return;
}
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
xmm_coex_enable(modem, modem_data->chat);
return;
}
}
static int xmm7xxx_enable(struct ofono_modem *modem)
{
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
@@ -257,6 +1174,10 @@ static int xmm7xxx_enable(struct ofono_modem *modem)
g_at_chat_send(data->chat, "AT+CFUN=4", none_prefix,
cfun_enable_cb, modem, NULL);
data->netreg_watch = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_NETREG,
netreg_watch, modem, NULL);
return -EINPROGRESS;
}
@@ -287,6 +1208,11 @@ static int xmm7xxx_disable(struct ofono_modem *modem)
g_at_chat_send(data->chat, "AT+CFUN=0", none_prefix,
cfun_disable_cb, modem, NULL);
if (data->netreg_watch) {
__ofono_modem_remove_atom_watch(modem, data->netreg_watch);
data->netreg_watch = 0;
}
return -EINPROGRESS;
}

View File

@@ -29,6 +29,7 @@
<allow send_interface="org.ofono.HandsfreeAudioAgent"/>
<allow send_interface="org.ofono.VoiceCallAgent"/>
<allow send_interface="org.ofono.NetworkMonitorAgent"/>
<allow send_interface="org.ofono.intel.LteCoexistenceAgent"/>
</policy>
<policy at_console="true">

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2021 Jolla Ltd.
* Copyright (C) 2017-2022 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
@@ -183,7 +183,8 @@ static void slot_manager_reindex_slots(OfonoSlotManagerObject *mgr);
static void slot_manager_emit_all_queued_signals(OfonoSlotManagerObject *mgr);
static void slot_manager_update_ready(OfonoSlotManagerObject *mgr);
static enum slot_manager_dbus_signal slot_manager_update_modem_paths
(OfonoSlotManagerObject *mgr) G_GNUC_WARN_UNUSED_RESULT;
(OfonoSlotManagerObject *mgr, gboolean imsi_change)
G_GNUC_WARN_UNUSED_RESULT;
static inline OfonoSlotBase *slot_base_cast(gpointer p)
{
@@ -375,7 +376,7 @@ static inline void slot_manager_update_modem_paths_and_notify
(OfonoSlotManagerObject *mgr, enum slot_manager_dbus_signal extra)
{
slot_manager_dbus_signal(mgr->dbus, extra |
slot_manager_update_modem_paths(mgr));
slot_manager_update_modem_paths(mgr, FALSE));
}
static void slot_update_data_role(OfonoSlotObject *slot,
@@ -421,34 +422,9 @@ static void slot_manager_slot_imsi_changed(struct ofono_watch *w, void *data)
{
OfonoSlotObject *slot = OFONO_SLOT_OBJECT(data);
OfonoSlotManagerObject *mgr = slot->manager;
OfonoSlotObject *voice_slot = mgr->voice_slot;
OfonoSlotObject *data_slot = mgr->data_slot;
int signal_mask;
/*
* We want the first slot to be selected by default.
* However, things may become available in pretty much
* any order, so reset the slot pointers to NULL and let
* slot_manager_update_modem_paths() to pick them again.
*/
mgr->voice_slot = NULL;
mgr->data_slot = NULL;
mgr->pub.default_voice_path = NULL;
mgr->pub.default_data_path = NULL;
signal_mask = slot_manager_update_modem_paths(mgr);
if (voice_slot != mgr->voice_slot) {
if (!mgr->voice_slot) {
DBG("No default voice SIM");
}
signal_mask |= SLOT_MANAGER_DBUS_SIGNAL_VOICE_PATH;
}
if (data_slot != mgr->data_slot) {
if (!mgr->data_slot) {
DBG("No default data SIM");
}
signal_mask |= SLOT_MANAGER_DBUS_SIGNAL_DATA_PATH;
}
slot_manager_dbus_signal(mgr->dbus, signal_mask);
slot_manager_dbus_signal(mgr->dbus,
slot_manager_update_modem_paths(mgr, TRUE));
slot_manager_emit_all_queued_signals(mgr);
}
@@ -707,7 +683,7 @@ static gboolean slot_manager_all_sims_are_initialized
* queued signals mask but doesn't actually emit any signals.
*/
static enum slot_manager_dbus_signal slot_manager_update_modem_paths
(OfonoSlotManagerObject *mgr)
(OfonoSlotManagerObject *mgr, gboolean imsi_change)
{
enum slot_manager_dbus_signal mask = SLOT_MANAGER_DBUS_SIGNAL_NONE;
OfonoSlotObject *slot = NULL;
@@ -719,7 +695,7 @@ static enum slot_manager_dbus_signal slot_manager_update_modem_paths
if (mgr->default_voice_imsi) {
slot = slot_manager_find_slot_imsi(mgr,
mgr->default_voice_imsi);
} else if (mgr->voice_slot) {
} else if (mgr->voice_slot && !imsi_change) {
/* Make sure that the slot is enabled and SIM is in */
slot = slot_manager_find_slot_imsi(mgr,
mgr->voice_slot->watch->imsi);

View File

@@ -10,7 +10,7 @@ if len(sys.argv) == 5:
pin_type = sys.argv[2]
old_pin = sys.argv[3]
new_pin = sys.argv[4]
elif len(sys.argv) == 3:
elif len(sys.argv) == 4:
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
'org.ofono.Manager')
modems = manager.GetModems()

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2021 Jolla Ltd.
* Copyright (C) 2017-2022 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
@@ -51,6 +51,12 @@
#define TEST_SLOT_ERROR_KEY "SlotError"
#define TEST_CONFIG_DIR_TEMPLATE "test-saifish_manager-config-XXXXXX"
#define SM_STORE "ril"
#define SM_STORE_GROUP "Settings"
#define SM_STORE_ENABLED_SLOTS "EnabledSlots"
#define SM_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim"
#define SM_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
static GMainLoop *test_loop = NULL;
static GSList *test_drivers = NULL;
static struct ofono_slot_driver_reg *test_driver_reg = NULL;
@@ -1141,6 +1147,7 @@ static gboolean test_data_sim_done(gpointer user_data)
/* Set data SIM IMSI */
fake_slot_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI);
g_assert_cmpstr(m->default_data_imsi, == ,TEST_IMSI);
g_assert_cmpint(s->data_role, == ,OFONO_SLOT_DATA_NONE);
g_assert(!m->default_data_path); /* Modem is offline */
/* Data IMSI is signaled, path is not */
g_assert_cmpuint(fake_slot_manager_dbus.signals &
@@ -1157,6 +1164,7 @@ static gboolean test_data_sim_done(gpointer user_data)
fake_watch_emit_queued_signals(w);
/* Now is should point to our slot */
g_assert_cmpstr(m->default_data_path, == ,TEST_PATH);
g_assert_cmpint(s->data_role, == ,OFONO_SLOT_DATA_INTERNET);
/* And D-Bus clients are notified */
g_assert(fake_slot_manager_dbus.signals &
SLOT_MANAGER_DBUS_SIGNAL_DATA_PATH);
@@ -1166,6 +1174,7 @@ static gboolean test_data_sim_done(gpointer user_data)
fake_slot_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI_1);
g_assert_cmpstr(m->default_data_imsi, == ,TEST_IMSI_1);
g_assert(!m->default_data_path);
g_assert_cmpint(s->data_role, == ,OFONO_SLOT_DATA_NONE);
/* And D-Bus clients are notified again */
g_assert_cmpuint(fake_slot_manager_dbus.signals &
(SLOT_MANAGER_DBUS_SIGNAL_DATA_IMSI |
@@ -1177,8 +1186,10 @@ static gboolean test_data_sim_done(gpointer user_data)
/* Switch the SIM */
fake_watch_set_ofono_imsi(w, TEST_IMSI_1);
fake_watch_set_ofono_iccid(w, TEST_ICCID_1);
fake_watch_emit_queued_signals(w);
g_assert_cmpstr(m->default_data_path, == ,TEST_PATH);
g_assert_cmpint(s->data_role, == ,OFONO_SLOT_DATA_INTERNET);
/* And D-Bus clients are notified of data path change */
g_assert_cmpuint(fake_slot_manager_dbus.signals &
(SLOT_MANAGER_DBUS_SIGNAL_DATA_IMSI |
@@ -1193,6 +1204,7 @@ static gboolean test_data_sim_done(gpointer user_data)
g_assert_cmpint(m->slots[0]->sim_presence, == ,OFONO_SLOT_SIM_ABSENT);
g_assert_cmpstr(m->default_data_imsi, == ,TEST_IMSI_1);
g_assert(!m->default_data_path);
g_assert_cmpint(s->data_role, == ,OFONO_SLOT_DATA_NONE);
/* And D-Bus clients are notified of data path change */
g_assert_cmpuint(fake_slot_manager_dbus.signals &
(SLOT_MANAGER_DBUS_SIGNAL_DATA_IMSI |
@@ -1200,6 +1212,20 @@ static gboolean test_data_sim_done(gpointer user_data)
SLOT_MANAGER_DBUS_SIGNAL_DATA_PATH);
fake_slot_manager_dbus.signals &= ~SLOT_MANAGER_DBUS_SIGNAL_DATA_IMSI;
/* Insert the SIM back */
fake_watch_set_ofono_sim(w, &sim);
ofono_slot_set_sim_presence(s, OFONO_SLOT_SIM_PRESENT);
g_assert_cmpint(s->sim_presence, == ,OFONO_SLOT_SIM_PRESENT);
fake_watch_set_ofono_iccid(w, TEST_ICCID_1);
fake_watch_set_ofono_imsi(w, TEST_IMSI_1);
fake_watch_emit_queued_signals(w);
g_assert_cmpint(s->data_role, == ,OFONO_SLOT_DATA_INTERNET);
g_assert_cmpuint(fake_slot_manager_dbus.signals &
(SLOT_MANAGER_DBUS_SIGNAL_DATA_IMSI |
SLOT_MANAGER_DBUS_SIGNAL_DATA_PATH), == ,
SLOT_MANAGER_DBUS_SIGNAL_DATA_PATH);
fake_slot_manager_dbus.signals &= ~SLOT_MANAGER_DBUS_SIGNAL_DATA_IMSI;
ofono_watch_unref(w);
g_main_loop_quit(test_loop);
return G_SOURCE_REMOVE;
@@ -1629,6 +1655,102 @@ static void test_multisim(void)
test_common_deinit();
}
/* ==== config_storage ==== */
static gboolean test_config_storage_run(gpointer user_data)
{
TestDriverData *dd = user_data;
struct ofono_slot_manager *m = fake_slot_manager_dbus.m;
struct ofono_slot *s = ofono_slot_add(dd->manager, TEST_PATH,
OFONO_RADIO_ACCESS_MODE_GSM, TEST_IMEI, TEST_IMEISV,
OFONO_SLOT_SIM_PRESENT, OFONO_SLOT_NO_FLAGS);
struct ofono_slot *s2 = ofono_slot_add(dd->manager, TEST_PATH_1,
OFONO_RADIO_ACCESS_MODE_GSM, TEST_IMEI_1, TEST_IMEISV,
OFONO_SLOT_SIM_PRESENT, OFONO_SLOT_NO_FLAGS);
char *storage_file = g_build_filename(STORAGEDIR, SM_STORE, NULL);
GKeyFile *storage;
char **slots;
char* val;
DBG("");
/* Unblocking D-Bus clients will exit the loop */
fake_slot_manager_dbus.fn_block_changed =
test_quit_loop_when_unblocked;
/* Finish initialization with 2 slots */
g_assert(s);
g_assert(s2);
g_assert(!m->ready);
ofono_slot_driver_started(test_driver_reg);
ofono_slot_unref(s);
ofono_slot_unref(s2);
g_assert(m->ready);
/* No file yet */
storage = g_key_file_new();
g_assert(!g_key_file_load_from_file(storage, storage_file, 0, NULL));
/* Enable one slot */
slots = gutil_strv_add(NULL, TEST_PATH);
fake_slot_manager_dbus.cb.set_enabled_slots(m, slots);
g_assert(m->slots[0]->enabled);
g_assert(!m->slots[1]->enabled);
/* Check the config file */
g_assert(g_key_file_load_from_file(storage, storage_file, 0, NULL));
val = g_key_file_get_string(storage, SM_STORE_GROUP,
SM_STORE_ENABLED_SLOTS, NULL);
g_assert_cmpstr(val, == ,TEST_PATH);
g_free(val);
g_key_file_free(storage);
/* Enable both slots */
slots = gutil_strv_add(slots, TEST_PATH_1);
fake_slot_manager_dbus.cb.set_enabled_slots(m, slots);
g_assert(m->slots[0]->enabled);
g_assert(m->slots[1]->enabled);
g_strfreev(slots);
/* There's no [EnabledSlots] there because it's the default config */
storage = g_key_file_new();
g_assert(g_key_file_load_from_file(storage, storage_file, 0, NULL));
g_assert(!g_key_file_get_string(storage, SM_STORE_GROUP,
SM_STORE_ENABLED_SLOTS, NULL));
g_key_file_free(storage);
g_free(storage_file);
return G_SOURCE_REMOVE;
}
static guint test_config_storage_start(TestDriverData *dd)
{
return g_idle_add(test_config_storage_run, dd);
}
static void test_config_storage(void)
{
static const struct ofono_slot_driver test_config_storage_d = {
.name = "config_storage",
.api_version = OFONO_SLOT_API_VERSION,
.init = test_driver_init,
.start = test_config_storage_start,
.cleanup = test_driver_cleanup
};
test_common_init();
test_driver_reg = ofono_slot_driver_register(&test_config_storage_d);
g_assert(test_driver_reg);
g_main_loop_run(test_loop);
g_assert(test_timeout_id);
ofono_slot_driver_unregister(test_driver_reg);
test_driver_reg = NULL;
test_common_deinit();
}
/* ==== storage ==== */
static void test_storage_init()
@@ -1805,6 +1927,7 @@ int main(int argc, char *argv[])
g_test_add_data_func(TEST_("auto_data_sim_once"), "once",
test_auto_data_sim);
g_test_add_func(TEST_("multisim"), test_multisim);
g_test_add_func(TEST_("config_storage"), test_config_storage);
g_test_add_func(TEST_("storage"), test_storage);
return g_test_run();
}