mirror of
https://github.com/sailfishos/ofono
synced 2025-12-01 15:11:04 +08:00
Compare commits
34 Commits
mer/1.17+g
...
upgrade-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c572e83247 | ||
|
|
dd21e34a86 | ||
|
|
8de5892827 | ||
|
|
8b2ef760c7 | ||
|
|
0ee292e0f6 | ||
|
|
54209b39bd | ||
|
|
3ca442ad15 | ||
|
|
3a579dd7be | ||
|
|
a7266fc9c8 | ||
|
|
04dbd344b3 | ||
|
|
296534c2a8 | ||
|
|
6114482e2a | ||
|
|
8281885ba5 | ||
|
|
9cd3b84421 | ||
|
|
8d65aaefed | ||
|
|
ce15cfe48d | ||
|
|
3a1e37b498 | ||
|
|
ecef97dd83 | ||
|
|
a68f1e9c4d | ||
|
|
42808ed0f7 | ||
|
|
d896ebcb37 | ||
|
|
93c57284bd | ||
|
|
91436f9643 | ||
|
|
d0d2587b2a | ||
|
|
3e10878348 | ||
|
|
6de8c4aa85 | ||
|
|
a9da50f890 | ||
|
|
3ca5161a78 | ||
|
|
03b3ca7776 | ||
|
|
6e5316aba9 | ||
|
|
49b752f0ad | ||
|
|
268684eebf | ||
|
|
24db1db2b1 | ||
|
|
55977c1dac |
@@ -125,6 +125,8 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_forward.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_cell_info_dbus.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
|
||||
537
ofono/drivers/ril/ril_cell_info.c
Normal file
537
ofono/drivers/ril/ril_cell_info.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_mce.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
#include <grilio_parser.h>
|
||||
|
||||
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
|
||||
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
|
||||
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
struct ril_cell_info_priv {
|
||||
GRilIoChannel *io;
|
||||
struct ril_mce *mce;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
gulong display_state_event_id;
|
||||
gulong radio_state_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gboolean sim_card_ready;
|
||||
char *log_prefix;
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
guint set_rate_id;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
SIGNAL_CELLS_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_CELLS_CHANGED_NAME "ril-cell-info-cells-changed"
|
||||
|
||||
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO_TYPE (ril_cell_info_get_type())
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
|
||||
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
|
||||
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
|
||||
|
||||
if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
|
||||
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
|
||||
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
|
||||
|
||||
if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct ril_cell_info_lte *l1 = &c1->info.lte;
|
||||
const struct ril_cell_info_lte *l2 = &c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
|
||||
if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
return ril_cell_compare_location(v1, v2);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
l2 = l2->next;
|
||||
}
|
||||
return !l1 && !l2;
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->cells, l)) {
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
self->cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals[
|
||||
SIGNAL_CELLS_CHANGED], 0);
|
||||
} else {
|
||||
g_slist_free_full(l, g_free);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->lac) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->cid) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate)) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,"
|
||||
"strength=%d,err=%d", registered, gsm->mcc, gsm->mnc,
|
||||
gsm->lac, gsm->cid, gsm->signalStrength,
|
||||
gsm->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->cid) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->psc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
grilio_parser_get_int32(rilp, <e->pci) &&
|
||||
grilio_parser_get_int32(rilp, <e->tac) &&
|
||||
grilio_parser_get_int32(rilp, <e->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrp) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrq) &&
|
||||
grilio_parser_get_int32(rilp, <e->rssnr) &&
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=0x%x,rssnr=0x%x,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
cell->type = RIL_CELL_INFO_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
struct ril_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &type) &&
|
||||
grilio_parser_get_int32(rilp, ®) &&
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct ril_cell *cell = NULL;
|
||||
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
skip = 6;
|
||||
break;
|
||||
default:
|
||||
skip = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return type;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return RIL_CELL_INFO_TYPE_NONE;
|
||||
}
|
||||
|
||||
static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
{
|
||||
GSList *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
int i, n;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ril_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
ril_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->set_rate_id);
|
||||
priv->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = grilio_channel_send_request_full(priv->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
|
||||
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_cell_info_update_rate(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
ril_cell_info_set_rate(self,
|
||||
(priv->mce->display_state == RIL_MCE_DISPLAY_OFF) ?
|
||||
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
|
||||
}
|
||||
|
||||
static void ril_cell_info_display_state_cb(struct ril_mce *mce, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
|
||||
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
|
||||
ril_cell_info_refresh(self);
|
||||
}
|
||||
|
||||
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(arg);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
const gboolean sim_card_was_ready = priv->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (priv->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
|
||||
ril_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_mce *mce,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||
{
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->mce = ril_mce_ref(mce);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
priv->display_state_event_id =
|
||||
ril_mce_add_display_state_changed_handler(mce,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
priv->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (priv->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_CELL_INFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_unref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_CELL_INFO(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
|
||||
struct ril_cell_info_priv);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
|
||||
if (priv->query_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = 0;
|
||||
}
|
||||
if (priv->set_rate_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
|
||||
FALSE);
|
||||
priv->set_rate_id = 0;
|
||||
}
|
||||
if (priv->display_state_event_id) {
|
||||
ril_mce_remove_handler(priv->mce, priv->display_state_event_id);
|
||||
priv->display_state_event_id = 0;
|
||||
}
|
||||
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
ril_mce_unref(priv->mce);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
63
ofono/drivers/ril/ril_cell_info.h
Normal file
63
ofono/drivers/ril/ril_cell_info.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_CELL_INFO_H
|
||||
#define RIL_CELL_INFO_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_cell {
|
||||
enum ril_cell_info_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct ril_cell_info_gsm gsm;
|
||||
struct ril_cell_info_wcdma wcdma;
|
||||
struct ril_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
|
||||
struct ril_cell_info_priv;
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct ril_cell_info_priv *priv;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2);
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_mce *mce,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card);
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
|
||||
void ril_cell_info_unref(struct ril_cell_info *info);
|
||||
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
|
||||
const struct ril_cell *cell);
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
|
||||
ril_cell_info_cb_t cb, void *arg);
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
586
ofono/drivers/ril/ril_cell_info_dbus.c
Normal file
586
ofono/drivers/ril/ril_cell_info_dbus.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct ril_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct ril_cell cell;
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus {
|
||||
struct ril_modem *md;
|
||||
struct ril_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#define RIL_CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
|
||||
#define RIL_CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define RIL_CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
#define RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
|
||||
#define RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define RIL_CELL_DBUS_REMOVED_SIGNAL "Removed"
|
||||
|
||||
struct ril_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define RIL_CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_gsm,name), value }
|
||||
#define RIL_CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_wcdma,name), value }
|
||||
#define RIL_CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_lte,name), value }
|
||||
|
||||
static const struct ril_cell_property ril_cell_gsm_properties [] = {
|
||||
RIL_CELL_GSM_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_GSM_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_GSM_PROPERTY(0x04,lac),
|
||||
RIL_CELL_GSM_PROPERTY(0x08,cid),
|
||||
RIL_CELL_GSM_PROPERTY(0x10,signalStrength),
|
||||
RIL_CELL_GSM_PROPERTY(0x20,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_wcdma_properties [] = {
|
||||
RIL_CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x20,signalStrength),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x40,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_lte_properties [] = {
|
||||
RIL_CELL_LTE_PROPERTY(0x001,mcc),
|
||||
RIL_CELL_LTE_PROPERTY(0x002,mnc),
|
||||
RIL_CELL_LTE_PROPERTY(0x004,ci),
|
||||
RIL_CELL_LTE_PROPERTY(0x008,pci),
|
||||
RIL_CELL_LTE_PROPERTY(0x010,tac),
|
||||
RIL_CELL_LTE_PROPERTY(0x020,signalStrength),
|
||||
RIL_CELL_LTE_PROPERTY(0x040,rsrp),
|
||||
RIL_CELL_LTE_PROPERTY(0x080,rsrq),
|
||||
RIL_CELL_LTE_PROPERTY(0x100,rssnr),
|
||||
RIL_CELL_LTE_PROPERTY(0x200,cqi),
|
||||
RIL_CELL_LTE_PROPERTY(0x400,timingAdvance)
|
||||
};
|
||||
|
||||
#define RIL_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*ril_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry);
|
||||
|
||||
static const char *ril_cell_info_dbus_cell_type_str(enum ril_cell_info_type t)
|
||||
{
|
||||
switch (t) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
return "gsm";
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
return "cdma";
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
return "lte";
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
return "tdscdma";
|
||||
case RIL_CELL_INFO_TYPE_NONE:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ril_cell_property *ril_cell_info_dbus_cell_properties(
|
||||
enum ril_cell_info_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(ril_cell_gsm_properties);
|
||||
return ril_cell_gsm_properties;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(ril_cell_wcdma_properties);
|
||||
return ril_cell_wcdma_properties;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(ril_cell_lte_properties);
|
||||
return ril_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void ril_cell_info_destroy_entry(struct ril_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct ril_cell_entry *entry,
|
||||
ril_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = RIL_CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
const char *type = ril_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
for (i = 0; i < n; i++) {
|
||||
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
|
||||
if (value != INT_MAX) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
ril_cell_info_dbus_append_version(it, entry);
|
||||
ril_cell_info_dbus_append_type(it, entry);
|
||||
ril_cell_info_dbus_append_registered(it, entry);
|
||||
ril_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_type(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_registered(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_properties(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
ril_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
ril_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
ril_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_id(
|
||||
struct ril_cell_info_dbus *dbus, guint id)
|
||||
{
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint ril_cell_info_dbus_next_cell_id(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
while (ril_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_cell(
|
||||
struct ril_cell_info_dbus *dbus, const struct ril_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!ril_cell_compare_location(&entry->cell, cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_emit_path_list(struct ril_cell_info_dbus *dbus,
|
||||
const char *name, GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int ril_cell_info_dbus_compare(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_property_changed(struct ril_cell_info_dbus *dbus,
|
||||
const struct ril_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & RIL_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, RIL_CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_update_entries(struct ril_cell_info_dbus *dbus,
|
||||
gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
ril_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
struct ril_cell_entry *entry =
|
||||
ril_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = ril_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
ril_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct ril_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id = ril_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
ril_cell_info_dbus_cell_methods,
|
||||
ril_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_cells_changed_cb(struct ril_cell_info *info,
|
||||
void *arg)
|
||||
{
|
||||
DBG("");
|
||||
ril_cell_info_dbus_update_entries((struct ril_cell_info_dbus *)arg,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct ril_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
ril_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = ril_cell_info_ref(info);
|
||||
dbus->handler_id = ril_cell_info_add_cells_changed_handler(info,
|
||||
ril_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, ril_cell_info_dbus_methods,
|
||||
ril_cell_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ril_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_cell_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
ril_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
ril_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -277,6 +277,49 @@ enum ril_app_type {
|
||||
RIL_APPTYPE_ISIM = 5
|
||||
};
|
||||
|
||||
/* Cell info */
|
||||
enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_NONE = 0,
|
||||
RIL_CELL_INFO_TYPE_GSM = 1,
|
||||
RIL_CELL_INFO_TYPE_CDMA = 2,
|
||||
RIL_CELL_INFO_TYPE_LTE = 3,
|
||||
RIL_CELL_INFO_TYPE_WCDMA = 4,
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
struct ril_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_wcdma {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
|
||||
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_lte {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int ci; /* Cell Identity */
|
||||
int pci; /* Physical cell id (0..503) */
|
||||
int tac; /* Tracking area code */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
|
||||
int rsrp; /* Reference Signal Receive Power TS 36.133 */
|
||||
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
|
||||
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
|
||||
int cqi; /* Channel Quality Indicator TS 36.101 */
|
||||
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
|
||||
};
|
||||
|
||||
/* RIL Request Messages */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
|
||||
enum ril_data_priv_flags {
|
||||
RIL_DATA_FLAG_ALLOWED = 0x01,
|
||||
RIL_DATA_FLAG_ON = 0x02
|
||||
RIL_DATA_FLAG_MAX_SPEED = 0x02,
|
||||
RIL_DATA_FLAG_ON = 0x04
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -48,8 +49,13 @@ enum ril_data_priv_flags {
|
||||
*
|
||||
* There's one ril_data per slot.
|
||||
*
|
||||
* RIL_DATA_FLAG_ALLOWED is set for the last SIM for which ril_data_allow(TRUE)
|
||||
* was called. No more than one SIM at a time has this flag set.
|
||||
* RIL_DATA_FLAG_ALLOWED is set for the last SIM for which ril_data_allow()
|
||||
* was called with non-zero role. No more than one SIM at a time has this
|
||||
* flag set.
|
||||
*
|
||||
* RIL_DATA_FLAG_MAX_SPEED is set for the last SIM for which ril_data_allow()
|
||||
* was called with RIL_DATA_ROLE_INTERNET. No more than one SIM at a time has
|
||||
* this flag set.
|
||||
*
|
||||
* RIL_DATA_FLAG_ON is set for the active SIM after RIL_REQUEST_ALLOW_DATA
|
||||
* has successfully completed. For RIL version < 10 it's set immediately.
|
||||
@@ -167,8 +173,6 @@ struct ril_data_request_2g {
|
||||
static gboolean ril_data_manager_handover(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_disallow_all_except(struct ril_data_manager *dm,
|
||||
struct ril_data *allowed);
|
||||
|
||||
static void ril_data_power_update(struct ril_data *self);
|
||||
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
|
||||
@@ -842,7 +846,7 @@ static void ril_data_call_deact_cb(GRilIoChannel *io, int ril_status,
|
||||
/*
|
||||
* If RIL_REQUEST_DEACTIVATE_DATA_CALL succeeds, some RILs don't
|
||||
* send RIL_UNSOL_DATA_CALL_LIST_CHANGED even though the list of
|
||||
* calls has change. Update the list of calls to account for that.
|
||||
* calls has changed. Update the list of calls to account for that.
|
||||
*/
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
struct ril_data_call_list *list = data->data_calls;
|
||||
@@ -1138,22 +1142,76 @@ static void ril_data_disallow(struct ril_data *self)
|
||||
ril_data_power_update(self);
|
||||
}
|
||||
|
||||
void ril_data_allow(struct ril_data *self, gboolean allow)
|
||||
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
|
||||
{
|
||||
if (data != max_speed) {
|
||||
((struct ril_data *)data)->priv->flags &=
|
||||
~RIL_DATA_FLAG_MAX_SPEED;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_disallow_cb(gpointer data_ptr, gpointer allowed)
|
||||
{
|
||||
if (data_ptr != allowed) {
|
||||
struct ril_data *data = data_ptr;
|
||||
|
||||
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
const gboolean was_allowed = ril_data_allowed(data);
|
||||
ril_data_disallow(data);
|
||||
if (was_allowed) {
|
||||
ril_data_signal_emit(data,
|
||||
SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_data_allow(struct ril_data *self, enum ril_data_role role)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_data_manager *dm = priv->dm;
|
||||
|
||||
DBG_(self, "%s", allow ? "yes" : "no");
|
||||
if (allow) {
|
||||
if (!(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
DBG_(self, "%s", (role == RIL_DATA_ROLE_NONE) ? "none" :
|
||||
(role == RIL_DATA_ROLE_MMS) ? "mms" : "internet");
|
||||
|
||||
if (role != RIL_DATA_ROLE_NONE) {
|
||||
gboolean speed_changed = FALSE;
|
||||
if (role == RIL_DATA_ROLE_INTERNET &&
|
||||
!(priv->flags & RIL_DATA_FLAG_MAX_SPEED)) {
|
||||
priv->flags |= RIL_DATA_FLAG_MAX_SPEED;
|
||||
speed_changed = TRUE;
|
||||
|
||||
/*
|
||||
* Clear RIL_DATA_FLAG_MAX_SPEED for
|
||||
* all other slots
|
||||
*/
|
||||
g_slist_foreach(dm->data_list,
|
||||
ril_data_max_speed_cb, self);
|
||||
}
|
||||
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
/*
|
||||
* Data is already allowed for this slot,
|
||||
* just adjust the speed if necessary.
|
||||
*/
|
||||
if (speed_changed) {
|
||||
ril_data_manager_check_network_mode(dm);
|
||||
}
|
||||
} else {
|
||||
priv->flags |= RIL_DATA_FLAG_ALLOWED;
|
||||
priv->flags &= ~RIL_DATA_FLAG_ON;
|
||||
|
||||
/*
|
||||
* Clear RIL_DATA_FLAG_ALLOWED for all
|
||||
* other slots
|
||||
*/
|
||||
g_slist_foreach(dm->data_list,
|
||||
ril_data_disallow_cb, self);
|
||||
|
||||
ril_data_cancel_requests(self,
|
||||
DATA_REQUEST_FLAG_CANCEL_WHEN_ALLOWED);
|
||||
ril_data_power_update(self);
|
||||
ril_data_manager_disallow_all_except(dm, self);
|
||||
ril_data_manager_check_data(dm);
|
||||
ril_data_power_update(self);
|
||||
}
|
||||
} else {
|
||||
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
@@ -1285,34 +1343,6 @@ void ril_data_manager_unref(struct ril_data_manager *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_manager_disallow_all_except(struct ril_data_manager *self,
|
||||
struct ril_data *allowed)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
|
||||
if (data != allowed &&
|
||||
(data->priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
const gboolean was_allowed = ril_data_allowed(data);
|
||||
|
||||
/*
|
||||
* Since there cannot be more than one active data
|
||||
* SIM at a time, no more than one at a time can
|
||||
* get disallowed. We could break the loop once we
|
||||
* have found it but since the list is quite small,
|
||||
* why bother.
|
||||
*/
|
||||
ril_data_disallow(data);
|
||||
if (was_allowed) {
|
||||
ril_data_signal_emit(data,
|
||||
SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_data_manager_requests_pending(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *l;
|
||||
@@ -1332,7 +1362,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
GSList *l;
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
gboolean non_gsm_selected = FALSE;
|
||||
gboolean need_fast_access = FALSE;
|
||||
int non_gsm_count = 0;
|
||||
|
||||
/*
|
||||
@@ -1346,25 +1376,25 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM &&
|
||||
sim->imsi) {
|
||||
non_gsm_count++;
|
||||
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
non_gsm_selected = TRUE;
|
||||
if (priv->flags & RIL_DATA_FLAG_MAX_SPEED) {
|
||||
need_fast_access = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the selected data SIM has non-GSM mode enabled and
|
||||
* non-GSM mode is enabled for more than one SIM, then
|
||||
* we need to limit other SIMs to GSM. Otherwise, turn
|
||||
* all the limits off.
|
||||
* If the SIM selected for internet access has non-GSM mode
|
||||
* enabled and non-GSM mode is enabled for more than one SIM,
|
||||
* then we need to limit other SIMs to GSM. Otherwise, turn
|
||||
* all limits off.
|
||||
*/
|
||||
if (non_gsm_selected && non_gsm_count > 1) {
|
||||
if (need_fast_access && non_gsm_count > 1) {
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
|
||||
ril_network_set_max_pref_mode(priv->network,
|
||||
(priv->flags & RIL_DATA_FLAG_ALLOWED) ?
|
||||
(priv->flags & RIL_DATA_FLAG_MAX_SPEED) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
|
||||
@@ -54,6 +54,12 @@ enum ril_data_manager_flags {
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
|
||||
};
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Data not allowed */
|
||||
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
|
||||
};
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
@@ -79,7 +85,7 @@ gulong ril_data_add_calls_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
void ril_data_remove_handler(struct ril_data *data, gulong id);
|
||||
|
||||
void ril_data_allow(struct ril_data *data, gboolean allow);
|
||||
void ril_data_allow(struct ril_data *data, enum ril_data_role role);
|
||||
|
||||
struct ril_data_request;
|
||||
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
|
||||
|
||||
@@ -38,7 +38,7 @@ enum ril_ecclist_signal {
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_LIST_CHANGED_NAME "ril-sim-settings-imsi-changed"
|
||||
#define SIGNAL_LIST_CHANGED_NAME "ril-ecclist-changed"
|
||||
|
||||
static guint ril_ecclist_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
|
||||
@@ -105,24 +105,6 @@ static void ril_gprs_context_set_ipv6(struct ofono_gprs_context *gc,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_call_done(struct ril_gprs_context_call *call,
|
||||
gboolean ok)
|
||||
{
|
||||
ofono_gprs_context_cb_t cb = call->cb;
|
||||
gpointer data = call->data;
|
||||
|
||||
ril_data_request_cancel(call->req);
|
||||
|
||||
call->req = NULL;
|
||||
call->cb = NULL;
|
||||
call->data = NULL;
|
||||
|
||||
if (cb) {
|
||||
struct ofono_error error;
|
||||
cb(ok ? ril_error_ok(&error) : ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
{
|
||||
if (gcd->active_call) {
|
||||
@@ -159,7 +141,29 @@ static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
|
||||
if (gcd->active_call) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
if (gcd->deactivate.req) {
|
||||
ril_gprs_context_call_done(&gcd->deactivate, TRUE);
|
||||
struct ril_gprs_context_call deact = gcd->deactivate;
|
||||
|
||||
/*
|
||||
* Complete the deactivate request. We need to
|
||||
* clear gcd->deactivate first because cancelling
|
||||
* the deactivation request will probably result
|
||||
* in ril_gprs_context_deactivate_primary_cb() being
|
||||
* invoked with GRILIO_CANCELLED status. And we don't
|
||||
* want to fail the disconnect request because this
|
||||
* is a success (we wanted to disconnect the data
|
||||
* call and it's gone).
|
||||
*
|
||||
* Additionally, we need to make sure that we don't
|
||||
* complete the same request twice - that would crash
|
||||
* the core.
|
||||
*/
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
ril_data_request_cancel(deact.req);
|
||||
if (deact.cb) {
|
||||
struct ofono_error error;
|
||||
ofono_info("Deactivated data call");
|
||||
deact.cb(ril_error_ok(&error), deact.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gcd->active_ctx_cid != CTX_ID_NONE) {
|
||||
@@ -549,32 +553,37 @@ static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
|
||||
int ril_status, void *user_data)
|
||||
{
|
||||
struct ril_gprs_context *gcd = user_data;
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb;
|
||||
gpointer cb_data;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
GASSERT(gcd->active_call);
|
||||
ril_error_init_ok(&error);
|
||||
ofono_info("Deactivated data call");
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
ofono_error("Deactivate failure: %s",
|
||||
/*
|
||||
* Data call list may change before the completion of the deactivate
|
||||
* request, in that case ril_gprs_context_set_disconnected will be
|
||||
* invoked and gcd->deactivate.req will be NULL.
|
||||
*/
|
||||
if (gcd->deactivate.req) {
|
||||
struct ofono_error error;
|
||||
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
|
||||
gpointer cb_data = gcd->deactivate.data;
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
GASSERT(gcd->active_call);
|
||||
ril_error_init_ok(&error);
|
||||
ofono_info("Deactivated data call");
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
ofono_error("Deactivate failure: %s",
|
||||
ril_error_to_string(ril_status));
|
||||
}
|
||||
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
if (cb) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cb = gcd->deactivate.cb;
|
||||
cb_data = gcd->deactivate.data;
|
||||
GASSERT(gcd->deactivate.req);
|
||||
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
|
||||
|
||||
if (cb) {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
cb(&error, cb_data);
|
||||
} else {
|
||||
/* Have to tell ofono that the call has been disconnected */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
/* Make sure we are in the disconnected state */
|
||||
ril_gprs_context_set_disconnected(gcd);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,118 +14,251 @@
|
||||
*/
|
||||
|
||||
#include "ril_mce.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
/* <mce/dbus-names.h> */
|
||||
#define MCE_SERVICE "com.nokia.mce"
|
||||
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
|
||||
#define MCE_REQUEST_IF "com.nokia.mce.request"
|
||||
#define MCE_REQUEST_PATH "/com/nokia/mce/request"
|
||||
#define MCE_DISPLAY_STATUS_GET "get_display_status"
|
||||
#define MCE_DISPLAY_SIG "display_status_ind"
|
||||
#define MCE_DISPLAY_DIM_STRING "dimmed"
|
||||
#define MCE_DISPLAY_ON_STRING "on"
|
||||
#define MCE_DISPLAY_OFF_STRING "off"
|
||||
|
||||
struct ril_mce {
|
||||
typedef GObjectClass RilMceClass;
|
||||
typedef struct ril_mce RilMce;
|
||||
|
||||
struct ril_mce_priv {
|
||||
GRilIoChannel *io;
|
||||
DBusConnection *conn;
|
||||
int screen_state;
|
||||
DBusPendingCall *req;
|
||||
guint daemon_watch;
|
||||
guint signal_watch;
|
||||
};
|
||||
|
||||
static void ril_mce_send_screen_state(struct ril_mce *mce, gboolean on)
|
||||
enum ril_mce_signal {
|
||||
SIGNAL_DISPLAY_STATE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_DISPLAY_STATE_CHANGED_NAME "ril-mce-display-state-changed"
|
||||
|
||||
static guint ril_mce_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilMce, ril_mce, G_TYPE_OBJECT)
|
||||
#define RIL_MCE_TYPE (ril_mce_get_type())
|
||||
#define RIL_MCE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_MCE_TYPE,RilMce))
|
||||
|
||||
static const char *ril_mce_display_state_string(enum ril_mce_display_state ds)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
switch (ds) {
|
||||
case RIL_MCE_DISPLAY_OFF:
|
||||
return MCE_DISPLAY_OFF_STRING;
|
||||
case RIL_MCE_DISPLAY_DIM:
|
||||
return MCE_DISPLAY_DIM_STRING;
|
||||
case RIL_MCE_DISPLAY_ON:
|
||||
return MCE_DISPLAY_ON_STRING;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, on); /* screen on/off */
|
||||
static enum ril_mce_display_state ril_mce_parse_display_state(DBusMessage *msg)
|
||||
{
|
||||
DBusMessageIter it;
|
||||
|
||||
grilio_channel_send_request(mce->io, req, RIL_REQUEST_SCREEN_STATE);
|
||||
grilio_request_unref(req);
|
||||
if (dbus_message_iter_init(msg, &it) &&
|
||||
dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_STRING) {
|
||||
const char *value = NULL;
|
||||
|
||||
dbus_message_iter_get_basic(&it, &value);
|
||||
if (!g_strcmp0(value, MCE_DISPLAY_OFF_STRING)) {
|
||||
return RIL_MCE_DISPLAY_OFF;
|
||||
} else if (!g_strcmp0(value, MCE_DISPLAY_DIM_STRING)) {
|
||||
return RIL_MCE_DISPLAY_DIM;
|
||||
} else {
|
||||
GASSERT(!g_strcmp0(value, MCE_DISPLAY_ON_STRING));
|
||||
}
|
||||
}
|
||||
|
||||
return RIL_MCE_DISPLAY_ON;
|
||||
}
|
||||
|
||||
static void ril_mce_update_display_state(struct ril_mce *self,
|
||||
enum ril_mce_display_state state)
|
||||
{
|
||||
if (self->display_state != state) {
|
||||
self->display_state = state;
|
||||
g_signal_emit(self, ril_mce_signals[
|
||||
SIGNAL_DISPLAY_STATE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_mce_display_changed(DBusConnection *conn,
|
||||
DBusMessage *message, void *user_data)
|
||||
DBusMessage *msg, void *user_data)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
if (dbus_message_iter_init(message, &iter) &&
|
||||
dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
struct ril_mce *mce = user_data;
|
||||
const char *value = NULL;
|
||||
int state;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
DBG(" %s", value);
|
||||
|
||||
/* It is on if it's not off */
|
||||
state = (g_strcmp0(value, MCE_DISPLAY_OFF_STRING) != 0);
|
||||
if (mce->screen_state != state) {
|
||||
mce->screen_state = state;
|
||||
ril_mce_send_screen_state(mce, state);
|
||||
}
|
||||
} else {
|
||||
DBG("");
|
||||
}
|
||||
enum ril_mce_display_state state = ril_mce_parse_display_state(msg);
|
||||
|
||||
DBG("%s", ril_mce_display_state_string(state));
|
||||
ril_mce_update_display_state(RIL_MCE(user_data), state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ril_mce_display_status_reply(DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(user_data);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
enum ril_mce_display_state state = ril_mce_parse_display_state(reply);
|
||||
|
||||
GASSERT(priv->req);
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(priv->req);
|
||||
priv->req = NULL;
|
||||
|
||||
DBG("%s", ril_mce_display_state_string(state));
|
||||
ril_mce_update_display_state(self, state);
|
||||
}
|
||||
|
||||
static void ril_mce_connect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
struct ril_mce *mce = user_data;
|
||||
struct ril_mce *self = RIL_MCE(user_data);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
DBG("");
|
||||
if (!mce->signal_watch) {
|
||||
mce->signal_watch = g_dbus_add_signal_watch(conn,
|
||||
if (!priv->req) {
|
||||
DBusMessage *msg = dbus_message_new_method_call(MCE_SERVICE,
|
||||
MCE_REQUEST_PATH, MCE_REQUEST_IF,
|
||||
MCE_DISPLAY_STATUS_GET);
|
||||
if (g_dbus_send_message_with_reply(conn, msg, &priv->req, -1)) {
|
||||
dbus_pending_call_set_notify(priv->req,
|
||||
ril_mce_display_status_reply,
|
||||
self, NULL);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
}
|
||||
if (!priv->signal_watch) {
|
||||
priv->signal_watch = g_dbus_add_signal_watch(conn,
|
||||
MCE_SERVICE, NULL, MCE_SIGNAL_IF, MCE_DISPLAY_SIG,
|
||||
ril_mce_display_changed, mce, NULL);
|
||||
ril_mce_display_changed, self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mce_disconnect(DBusConnection *conn, void *user_data)
|
||||
{
|
||||
struct ril_mce *mce = user_data;
|
||||
struct ril_mce *self = user_data;
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
DBG("");
|
||||
if (mce->signal_watch) {
|
||||
g_dbus_remove_watch(conn, mce->signal_watch);
|
||||
mce->signal_watch = 0;
|
||||
if (priv->signal_watch) {
|
||||
g_dbus_remove_watch(conn, priv->signal_watch);
|
||||
priv->signal_watch = 0;
|
||||
}
|
||||
if (priv->req) {
|
||||
dbus_pending_call_cancel(priv->req);
|
||||
dbus_pending_call_unref(priv->req);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_mce *ril_mce_new(GRilIoChannel *io)
|
||||
struct ril_mce *ril_mce_new()
|
||||
{
|
||||
struct ril_mce *mce = g_new0(struct ril_mce, 1);
|
||||
struct ril_mce *self = g_object_new(RIL_MCE_TYPE, NULL);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
mce->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
mce->io = grilio_channel_ref(io);
|
||||
mce->screen_state = -1;
|
||||
mce->daemon_watch = g_dbus_add_service_watch(mce->conn, MCE_SERVICE,
|
||||
ril_mce_connect, ril_mce_disconnect, mce, NULL);
|
||||
|
||||
return mce;
|
||||
DBG("");
|
||||
priv->daemon_watch = g_dbus_add_service_watch(priv->conn, MCE_SERVICE,
|
||||
ril_mce_connect, ril_mce_disconnect, self, NULL);
|
||||
return self;
|
||||
}
|
||||
|
||||
void ril_mce_free(struct ril_mce *mce)
|
||||
struct ril_mce *ril_mce_ref(struct ril_mce *self)
|
||||
{
|
||||
if (mce) {
|
||||
if (mce->signal_watch) {
|
||||
g_dbus_remove_watch(mce->conn, mce->signal_watch);
|
||||
}
|
||||
if (mce->daemon_watch) {
|
||||
g_dbus_remove_watch(mce->conn, mce->daemon_watch);
|
||||
}
|
||||
dbus_connection_unref(mce->conn);
|
||||
grilio_channel_unref(mce->io);
|
||||
g_free(mce);
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_MCE(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_mce_unref(struct ril_mce *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_MCE(self));
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_mce_add_display_state_changed_handler(struct ril_mce *self,
|
||||
ril_mce_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_DISPLAY_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_mce_remove_handler(struct ril_mce *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mce_init(struct ril_mce *self)
|
||||
{
|
||||
struct ril_mce_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_MCE_TYPE, struct ril_mce_priv);
|
||||
|
||||
priv->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
self->priv = priv;
|
||||
}
|
||||
|
||||
static void ril_mce_dispose(GObject *object)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(object);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
if (priv->signal_watch) {
|
||||
g_dbus_remove_watch(priv->conn, priv->signal_watch);
|
||||
priv->signal_watch = 0;
|
||||
}
|
||||
if (priv->daemon_watch) {
|
||||
g_dbus_remove_watch(priv->conn, priv->daemon_watch);
|
||||
priv->daemon_watch = 0;
|
||||
}
|
||||
if (priv->req) {
|
||||
dbus_pending_call_cancel(priv->req);
|
||||
dbus_pending_call_unref(priv->req);
|
||||
}
|
||||
G_OBJECT_CLASS(ril_mce_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_mce_finalize(GObject *object)
|
||||
{
|
||||
struct ril_mce *self = RIL_MCE(object);
|
||||
struct ril_mce_priv *priv = self->priv;
|
||||
|
||||
dbus_connection_unref(priv->conn);
|
||||
G_OBJECT_CLASS(ril_mce_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_mce_class_init(RilMceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_mce_dispose;
|
||||
object_class->finalize = ril_mce_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_mce_priv));
|
||||
ril_mce_signals[SIGNAL_DISPLAY_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_DISPLAY_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,8 +18,27 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_mce *ril_mce_new(GRilIoChannel *io);
|
||||
void ril_mce_free(struct ril_mce *mce);
|
||||
enum ril_mce_display_state {
|
||||
RIL_MCE_DISPLAY_OFF,
|
||||
RIL_MCE_DISPLAY_DIM,
|
||||
RIL_MCE_DISPLAY_ON
|
||||
};
|
||||
|
||||
struct ril_mce_priv;
|
||||
struct ril_mce {
|
||||
GObject object;
|
||||
struct ril_mce_priv *priv;
|
||||
enum ril_mce_display_state display_state;
|
||||
};
|
||||
|
||||
struct ril_mce *ril_mce_new(void);
|
||||
struct ril_mce *ril_mce_ref(struct ril_mce *mce);
|
||||
void ril_mce_unref(struct ril_mce *mce);
|
||||
|
||||
typedef void (*ril_mce_cb_t)(struct ril_mce *mce, void *arg);
|
||||
gulong ril_mce_add_display_state_changed_handler(struct ril_mce *mce,
|
||||
ril_mce_cb_t cb, void *arg);
|
||||
void ril_mce_remove_handler(struct ril_mce *mce, gulong id);
|
||||
|
||||
#endif /* RIL_MCE_H */
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ struct ril_modem_data {
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean devinfo_created;
|
||||
gboolean allow_data;
|
||||
|
||||
guint online_check_id;
|
||||
@@ -140,27 +139,6 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
md->online_cb_data = data;
|
||||
}
|
||||
|
||||
static void ril_modem_check_devinfo(struct ril_modem_data *md)
|
||||
{
|
||||
/* devinfo driver assumes that IMEI is known */
|
||||
if (md->imei && md->pre_sim_done && !md->devinfo_created &&
|
||||
md->modem.ofono) {
|
||||
md->devinfo_created = TRUE;
|
||||
ofono_devinfo_create(md->modem.ofono, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_modem_set_imei(struct ril_modem *modem, const char *imei)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
if (md) {
|
||||
g_free(md->imei);
|
||||
modem->imei = md->imei = g_strdup(imei);
|
||||
ril_modem_check_devinfo(md);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
@@ -273,7 +251,7 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
md->pre_sim_done = TRUE;
|
||||
ril_modem_check_devinfo(md);
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ril_modem_update_radio_settings(md);
|
||||
@@ -443,6 +421,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
/*
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(slot->imei);
|
||||
|
||||
/* Copy config */
|
||||
modem->config = *slot->config;
|
||||
modem->imei = md->imei = g_strdup(slot->imei);
|
||||
|
||||
@@ -403,10 +403,13 @@ static void ril_netreg_strength(struct ofono_netreg *netreg,
|
||||
ofono_netreg_strength_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_queue_send_request_full(nd->q, NULL,
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SIGNAL_STRENGTH, ril_netreg_strength_cb,
|
||||
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_info.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_data.h"
|
||||
@@ -83,6 +84,9 @@ struct ril_plugin_priv {
|
||||
struct ril_plugin pub;
|
||||
struct ril_plugin_dbus *dbus;
|
||||
struct ril_data_manager *data_manager;
|
||||
struct ril_mce *mce;
|
||||
gboolean display_on;
|
||||
gulong display_state_change_id;
|
||||
GSList *slots;
|
||||
ril_slot_info_ptr *slots_info;
|
||||
struct ril_slot *voice_slot;
|
||||
@@ -116,6 +120,8 @@ struct ril_slot {
|
||||
struct ril_sim_info *sim_info;
|
||||
struct ril_sim_info_dbus *sim_info_dbus;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_cell_info *cell_info;
|
||||
struct ril_cell_info_dbus *cell_info_dbus;
|
||||
struct ril_data *data;
|
||||
GRilIoChannel *io;
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
@@ -187,6 +193,29 @@ static void ril_plugin_foreach_slot(struct ril_plugin_priv *plugin,
|
||||
g_slist_foreach(plugin->slots, ril_plugin_foreach_slot_proc, fn);
|
||||
}
|
||||
|
||||
static void ril_plugin_send_screen_state(struct ril_slot *slot)
|
||||
{
|
||||
if (slot->io) {
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
grilio_request_append_int32(req, 1); /* Number of params */
|
||||
grilio_request_append_int32(req, slot->plugin->display_on);
|
||||
grilio_channel_send_request(slot->io, req,
|
||||
RIL_REQUEST_SCREEN_STATE);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_display_state_cb(struct ril_mce *mce, void *user_data)
|
||||
{
|
||||
struct ril_plugin_priv *plugin = user_data;
|
||||
const gboolean display_was_on = plugin->display_on;
|
||||
|
||||
plugin->display_on = (mce->display_state != RIL_MCE_DISPLAY_OFF);
|
||||
if (plugin->display_on != display_was_on) {
|
||||
ril_plugin_foreach_slot(plugin, ril_plugin_send_screen_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_remove_slot_handler(struct ril_slot *slot, int id)
|
||||
{
|
||||
GASSERT(id >= 0 && id<IO_EVENT_COUNT);
|
||||
@@ -233,18 +262,18 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
|
||||
GASSERT(!slot->sim_watch_id);
|
||||
|
||||
if (kill_io) {
|
||||
if (slot->mce) {
|
||||
ril_mce_free(slot->mce);
|
||||
slot->mce = NULL;
|
||||
}
|
||||
|
||||
if (slot->retry_id) {
|
||||
g_source_remove(slot->retry_id);
|
||||
slot->retry_id = 0;
|
||||
}
|
||||
|
||||
if (slot->cell_info) {
|
||||
ril_cell_info_unref(slot->cell_info);
|
||||
slot->cell_info = NULL;
|
||||
}
|
||||
|
||||
if (slot->data) {
|
||||
ril_data_allow(slot->data, FALSE);
|
||||
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
|
||||
ril_data_unref(slot->data);
|
||||
slot->data = NULL;
|
||||
}
|
||||
@@ -255,6 +284,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
|
||||
}
|
||||
|
||||
if (slot->network) {
|
||||
ril_sim_info_set_network(slot->sim_info, slot->network);
|
||||
ril_network_unref(slot->network);
|
||||
slot->network = NULL;
|
||||
}
|
||||
@@ -454,10 +484,12 @@ static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
|
||||
if (old_data_slot != new_data_slot) {
|
||||
/* Yes we are switching data SIMs */
|
||||
if (old_data_slot) {
|
||||
ril_data_allow(old_data_slot->data, FALSE);
|
||||
ril_data_allow(old_data_slot->data, RIL_DATA_ROLE_NONE);
|
||||
}
|
||||
if (new_data_slot) {
|
||||
ril_data_allow(new_data_slot->data, TRUE);
|
||||
ril_data_allow(new_data_slot->data,
|
||||
(new_data_slot == plugin->data_slot) ?
|
||||
RIL_DATA_ROLE_INTERNET : RIL_DATA_ROLE_MMS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,8 +518,9 @@ static void ril_plugin_update_ready(struct ril_plugin_priv *plugin)
|
||||
}
|
||||
|
||||
if (plugin->pub.ready != ready) {
|
||||
DBG("%sready", ready ? "" : "not ");
|
||||
plugin->pub.ready = ready;
|
||||
ril_plugin_dbus_block_imei_requests(plugin->dbus, !ready);
|
||||
DBG("%sready", ready ? "" : "not ");
|
||||
ril_plugin_dbus_signal(plugin->dbus, RIL_PLUGIN_SIGNAL_READY);
|
||||
}
|
||||
}
|
||||
@@ -646,9 +679,14 @@ static void ril_plugin_modem_removed(struct ril_modem *modem, void *data)
|
||||
slot->sim_info_dbus = NULL;
|
||||
}
|
||||
|
||||
if (slot->cell_info_dbus) {
|
||||
ril_cell_info_dbus_free(slot->cell_info_dbus);
|
||||
slot->cell_info_dbus = NULL;
|
||||
}
|
||||
|
||||
slot->modem = NULL;
|
||||
ril_radio_set_online(slot->radio, FALSE);
|
||||
ril_data_allow(slot->data, FALSE);
|
||||
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
@@ -735,11 +773,6 @@ static const char *ril_plugin_log_prefix(struct ril_slot *slot)
|
||||
return ril_plugin_multisim(slot->plugin) ? (slot->path + 1) : "";
|
||||
}
|
||||
|
||||
static gboolean ril_plugin_can_create_modem(struct ril_slot *slot)
|
||||
{
|
||||
return slot->pub.enabled && slot->io && slot->io->connected;
|
||||
}
|
||||
|
||||
static void ril_plugin_create_modem(struct ril_slot *slot)
|
||||
{
|
||||
struct ril_modem *modem;
|
||||
@@ -766,6 +799,11 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
|
||||
|
||||
slot->sim_info_dbus = ril_sim_info_dbus_new(slot->modem,
|
||||
slot->sim_info);
|
||||
if (slot->cell_info) {
|
||||
slot->cell_info_dbus =
|
||||
ril_cell_info_dbus_new(slot->modem,
|
||||
slot->cell_info);
|
||||
}
|
||||
|
||||
ril_modem_set_removed_cb(modem, ril_plugin_modem_removed, slot);
|
||||
ril_modem_set_online_cb(modem, ril_plugin_modem_online, slot);
|
||||
@@ -776,42 +814,49 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
|
||||
ril_plugin_update_modem_paths_full(slot->plugin);
|
||||
}
|
||||
|
||||
static void ril_plugin_check_modem(struct ril_slot *slot)
|
||||
{
|
||||
if (!slot->modem && slot->pub.enabled &&
|
||||
slot->io && slot->io->connected &&
|
||||
!slot->imei_req_id && slot->imei) {
|
||||
ril_plugin_create_modem(slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_slot *slot = user_data;
|
||||
struct ril_plugin_priv *plugin = slot->plugin;
|
||||
gboolean all_done = TRUE;
|
||||
GSList *link;
|
||||
char *imei = NULL;
|
||||
|
||||
GASSERT(!slot->imei);
|
||||
GASSERT(slot->imei_req_id);
|
||||
slot->imei_req_id = 0;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
slot->pub.imei = slot->imei = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", slot->imei);
|
||||
if (slot->modem) {
|
||||
ril_modem_set_imei(slot->modem, slot->imei);
|
||||
}
|
||||
ril_plugin_update_ready(plugin);
|
||||
imei = grilio_parser_get_utf8(&rilp);
|
||||
|
||||
DBG("%s", imei);
|
||||
|
||||
/*
|
||||
* slot->imei should be either NULL (when we get connected
|
||||
* to rild the very first time) or match the already known
|
||||
* IMEI (if rild crashed and we have reconnected)
|
||||
*/
|
||||
GASSERT(!slot->imei || !g_strcmp0(slot->imei, imei));
|
||||
} else {
|
||||
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
|
||||
ril_error_to_string(status));
|
||||
}
|
||||
|
||||
for (link = plugin->slots; link && all_done; link = link->next) {
|
||||
if (((struct ril_slot *)link->data)->imei_req_id) {
|
||||
all_done = FALSE;
|
||||
}
|
||||
}
|
||||
g_free(slot->imei);
|
||||
slot->pub.imei = slot->imei = (imei ? imei : g_strdup("ERROR"));
|
||||
|
||||
if (all_done) {
|
||||
DBG("all done");
|
||||
ril_plugin_dbus_block_imei_requests(plugin->dbus, FALSE);
|
||||
}
|
||||
ril_plugin_check_modem(slot);
|
||||
ril_plugin_update_ready(slot->plugin);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -840,6 +885,7 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
|
||||
{
|
||||
struct ril_plugin_priv *plugin = slot->plugin;
|
||||
const char *log_prefix = ril_plugin_log_prefix(slot);
|
||||
GRilIoRequest* req;
|
||||
|
||||
ofono_debug("%s version %u", (slot->name && slot->name[0]) ?
|
||||
slot->name : "RIL", slot->io->ril_version);
|
||||
@@ -847,12 +893,19 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
|
||||
GASSERT(slot->io->connected);
|
||||
GASSERT(!slot->io_event_id[IO_EVENT_CONNECTED]);
|
||||
|
||||
GASSERT(!slot->mce);
|
||||
slot->mce = ril_mce_new(slot->io);
|
||||
|
||||
/*
|
||||
* Modem will be registered after RIL_REQUEST_GET_IMEI successfully
|
||||
* completes. By the time ofono starts, rild may not be completely
|
||||
* functional. Waiting until it responds to RIL_REQUEST_GET_IMEI
|
||||
* (and retrying the request on failure) gives rild time to finish
|
||||
* whatever it's doing during initialization.
|
||||
*/
|
||||
GASSERT(!slot->imei_req_id);
|
||||
slot->imei_req_id = grilio_channel_send_request_full(slot->io, NULL,
|
||||
req = grilio_request_new();
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
slot->imei_req_id = grilio_channel_send_request_full(slot->io, req,
|
||||
RIL_REQUEST_GET_IMEI, ril_plugin_imei_cb, NULL, slot);
|
||||
grilio_request_unref(req);
|
||||
|
||||
GASSERT(!slot->radio);
|
||||
slot->radio = ril_radio_new(slot->io);
|
||||
@@ -872,15 +925,20 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
|
||||
GASSERT(!slot->network);
|
||||
slot->network = ril_network_new(slot->io, log_prefix, slot->radio,
|
||||
slot->sim_card, slot->sim_settings);
|
||||
ril_sim_info_set_network(slot->sim_info, slot->network);
|
||||
|
||||
GASSERT(!slot->data);
|
||||
slot->data = ril_data_new(slot->plugin->data_manager, log_prefix,
|
||||
slot->radio, slot->network, slot->io);
|
||||
|
||||
if (ril_plugin_can_create_modem(slot) && !slot->modem) {
|
||||
ril_plugin_create_modem(slot);
|
||||
GASSERT(!slot->cell_info);
|
||||
if (slot->io->ril_version > 8) {
|
||||
slot->cell_info = ril_cell_info_new(slot->io, log_prefix,
|
||||
plugin->mce, slot->radio, slot->sim_card);
|
||||
}
|
||||
|
||||
ril_plugin_send_screen_state(slot);
|
||||
ril_plugin_check_modem(slot);
|
||||
ril_plugin_update_ready(plugin);
|
||||
}
|
||||
|
||||
@@ -1254,9 +1312,7 @@ static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
|
||||
{
|
||||
if (slot->pub.enabled) {
|
||||
DBG("%s enabled", slot->path + 1);
|
||||
if (ril_plugin_can_create_modem(slot) && !slot->modem) {
|
||||
ril_plugin_create_modem(slot);
|
||||
}
|
||||
ril_plugin_check_modem(slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1439,7 +1495,7 @@ static void ril_plugin_init_slots(struct ril_plugin_priv *plugin)
|
||||
slot->plugin = plugin;
|
||||
slot->pub.path = slot->path;
|
||||
slot->pub.config = &slot->config;
|
||||
slot->sim_info = ril_sim_info_new(NULL);
|
||||
slot->sim_info = ril_sim_info_new(ril_plugin_log_prefix(slot));
|
||||
slot->sim_settings = ril_sim_settings_new(&slot->config);
|
||||
}
|
||||
|
||||
@@ -1506,6 +1562,9 @@ static int ril_plugin_init(void)
|
||||
ril_plugin_init_slots(ril_plugin);
|
||||
ril_plugin->dbus = ril_plugin_dbus_new(&ril_plugin->pub);
|
||||
ril_plugin->data_manager = ril_data_manager_new(ps.dm_flags);
|
||||
ril_plugin->mce = ril_mce_new();
|
||||
ril_plugin->display_on =
|
||||
(ril_plugin->mce->display_state != RIL_MCE_DISPLAY_OFF);
|
||||
|
||||
if (ril_plugin->slots) {
|
||||
/*
|
||||
@@ -1574,6 +1633,12 @@ static int ril_plugin_init(void)
|
||||
*/
|
||||
ril_plugin_foreach_slot(ril_plugin, ril_plugin_init_io);
|
||||
|
||||
/* Set initial screen state and register for updates */
|
||||
ril_plugin_foreach_slot(ril_plugin, ril_plugin_send_screen_state);
|
||||
ril_plugin->display_state_change_id =
|
||||
ril_mce_add_display_state_changed_handler(ril_plugin->mce,
|
||||
ril_plugin_display_state_cb, ril_plugin);
|
||||
|
||||
/* This will set 'ready' flag if we have no modems at all */
|
||||
ril_plugin_update_ready(ril_plugin);
|
||||
return 0;
|
||||
@@ -1607,6 +1672,9 @@ static void ril_plugin_exit(void)
|
||||
g_slist_free_full(ril_plugin->slots, ril_plugin_destroy_slot);
|
||||
ril_plugin_dbus_free(ril_plugin->dbus);
|
||||
ril_data_manager_unref(ril_plugin->data_manager);
|
||||
ril_mce_remove_handler(ril_plugin->mce,
|
||||
ril_plugin->display_state_change_id);
|
||||
ril_mce_unref(ril_plugin->mce);
|
||||
g_key_file_free(ril_plugin->storage);
|
||||
g_free(ril_plugin->slots_info);
|
||||
g_free(ril_plugin->default_voice_imsi);
|
||||
|
||||
@@ -104,6 +104,11 @@ struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_sim_info *info);
|
||||
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
|
||||
|
||||
struct ril_cell_info_dbus;
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info);
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
|
||||
|
||||
struct ril_plugin_dbus;
|
||||
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
|
||||
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
|
||||
@@ -118,7 +123,6 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_network *network, struct ril_sim_card *card,
|
||||
struct ril_data *data, struct ril_sim_settings *settings);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
void ril_modem_set_imei(struct ril_modem *modem, const char *imei);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
|
||||
@@ -132,19 +136,6 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
#define ril_modem_slot(modem) ((modem)->config.slot)
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
void ril_sim_read_file_linear(struct ofono_sim *sim, int fileid,
|
||||
int record, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
|
||||
void ril_sim_read_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
int record, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
|
||||
void ril_sim_read_file_transparent(struct ofono_sim *sim, int fileid,
|
||||
int start, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
|
||||
void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_info_cb_t cb, void *data);
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
struct ril_sim {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
GRilIoQueue *q2;
|
||||
GList *pin_cbd_list;
|
||||
struct ofono_sim *sim;
|
||||
struct ril_sim_card *card;
|
||||
@@ -386,36 +385,19 @@ static guint ril_sim_request_io(struct ril_sim *sd, GRilIoQueue *q, int fileid,
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_sim_internal_read_file_info(struct ril_sim *sd, GRilIoQueue *q,
|
||||
int fileid, const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_info_cb_t cb, void *data)
|
||||
{
|
||||
if (!sd || !ril_sim_request_io(sd, q, fileid, CMD_GET_RESPONSE,
|
||||
0, 0, 15, path, path_len, ril_sim_file_info_cb,
|
||||
ril_sim_cbd_new(sd, cb, data))) {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), -1, -1, -1, NULL,
|
||||
EF_STATUS_INVALIDATED, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_ofono_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
const unsigned char *path, unsigned int len,
|
||||
ofono_sim_file_info_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
ril_sim_internal_read_file_info(sd, sd->q, fileid, path, len, cb, data);
|
||||
}
|
||||
|
||||
void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_info_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
ril_sim_internal_read_file_info(sd, sd->q2, fileid, path, path_len,
|
||||
cb, data);
|
||||
if (!sd || !ril_sim_request_io(sd, sd->q, fileid, CMD_GET_RESPONSE,
|
||||
0, 0, 15, path, len, ril_sim_file_info_cb,
|
||||
ril_sim_cbd_new(sd, cb, data))) {
|
||||
struct ofono_error error;
|
||||
cb(ril_error_failure(&error), -1, -1, -1, NULL,
|
||||
EF_STATUS_INVALIDATED, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_read_cb(GRilIoChannel *io, int status,
|
||||
@@ -458,42 +440,14 @@ static void ril_sim_read(struct ril_sim *sd, GRilIoQueue *q, int fileid,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ril_sim_internal_read_file_transparent(struct ril_sim *sd,
|
||||
GRilIoQueue *q, int fileid, int start, int length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
ril_sim_read(sd, q, fileid, CMD_READ_BINARY, (start >> 8),
|
||||
(start & 0xff), length, path, path_len, cb, data);
|
||||
}
|
||||
|
||||
static void ril_sim_ofono_read_file_transparent(struct ofono_sim *sim,
|
||||
int fileid, int start, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
ril_sim_internal_read_file_transparent(sd, sd->q, fileid, start, length,
|
||||
path, path_len, cb, data);
|
||||
}
|
||||
|
||||
void ril_sim_read_file_transparent(struct ofono_sim *sim, int fileid,
|
||||
int start, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
ril_sim_internal_read_file_transparent(sd, sd->q2, fileid, start,
|
||||
length, path, path_len, cb, data);
|
||||
}
|
||||
|
||||
static inline void ril_sim_internal_read_file_linear(struct ril_sim *sd,
|
||||
GRilIoQueue *q, int fileid, int record, int length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
ril_sim_read(sd, q, fileid, CMD_READ_RECORD, record, 4, length,
|
||||
path, path_len, cb, data);
|
||||
ril_sim_read(sd, sd->q, fileid, CMD_READ_BINARY, (start >> 8),
|
||||
(start & 0xff), length, path, path_len, cb, data);
|
||||
}
|
||||
|
||||
static void ril_sim_ofono_read_file_linear(struct ofono_sim *sim, int fileid,
|
||||
@@ -502,29 +456,10 @@ static void ril_sim_ofono_read_file_linear(struct ofono_sim *sim, int fileid,
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
ril_sim_internal_read_file_linear(sd, sd->q, fileid, record, length,
|
||||
ril_sim_read(sd, sd->q, fileid, CMD_READ_RECORD, record, 4, length,
|
||||
path, path_len, cb, data);
|
||||
}
|
||||
|
||||
void ril_sim_read_file_linear(struct ofono_sim *sim, int fileid,
|
||||
int record, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
ril_sim_internal_read_file_linear(sd, sd->q2, fileid, record, length,
|
||||
path, path_len, cb, data);
|
||||
}
|
||||
|
||||
void ril_sim_read_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
int rec, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
/* Hmmm... Is this right? */
|
||||
ril_sim_read_file_linear(sim, fileid, rec, length, path, path_len,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
static void ril_sim_ofono_read_file_cyclic(struct ofono_sim *sim, int fileid,
|
||||
int rec, int length, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
|
||||
@@ -570,6 +505,13 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
DBG("%s", ril_sim_app_id(sd));
|
||||
grilio_request_append_int32(req, GET_IMSI_NUM_PARAMS);
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
|
||||
/*
|
||||
* If we fail the .read_imsi call, ofono gets into "Unable to
|
||||
* read IMSI, emergency calls only" state. Retry the request
|
||||
* on failure.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_GET_IMSI,
|
||||
ril_sim_get_imsi_cb, ril_sim_cbd_free,
|
||||
ril_sim_cbd_new(sd, cb, data));
|
||||
@@ -1045,18 +987,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
||||
sd->slot = ril_modem_slot(modem);
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->card = ril_sim_card_ref(modem->sim_card);
|
||||
|
||||
/* NB: One queue is used for the requests originated from the ofono
|
||||
* core, and the second one if for the requests initiated internally
|
||||
* by the RIL code.
|
||||
*
|
||||
* The difference is that when SIM card is removed, ofono requests
|
||||
* are cancelled without invoking the completion callbacks (otherwise
|
||||
* ofono would crash) while our completion callbacks have to be
|
||||
* notified in this case (otherwise we would leak memory)
|
||||
*/
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
sd->q2 = grilio_queue_new(sd->io);
|
||||
|
||||
DBG("[%u]", sd->slot);
|
||||
|
||||
@@ -1077,7 +1008,6 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
DBG("[%u]", sd->slot);
|
||||
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
grilio_queue_cancel_all(sd->q2, TRUE);
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
if (sd->idle_id) {
|
||||
@@ -1093,7 +1023,6 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
|
||||
grilio_channel_unref(sd->io);
|
||||
grilio_queue_unref(sd->q);
|
||||
grilio_queue_unref(sd->q2);
|
||||
g_free(sd);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ril_sim_info.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sim.h>
|
||||
@@ -29,10 +30,15 @@
|
||||
#define RIL_SIM_ICCID_MAP "iccidmap"
|
||||
#define RIL_SIM_ICCID_MAP_IMSI "imsi"
|
||||
|
||||
#define RIL_SIM_DEFAULT_SPN_BUFSIZE 8
|
||||
G_STATIC_ASSERT(RIL_SIM_DEFAULT_SPN_BUFSIZE >= \
|
||||
OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
|
||||
|
||||
typedef GObjectClass RilSimInfoClass;
|
||||
typedef struct ril_sim_info RilSimInfo;
|
||||
|
||||
typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim, unsigned int id);
|
||||
typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim,
|
||||
unsigned int id);
|
||||
typedef void (*ril_sim_info_set_value_cb_t)(struct ril_sim_info *info,
|
||||
const char *value);
|
||||
|
||||
@@ -44,14 +50,20 @@ struct ril_sim_info_watch {
|
||||
};
|
||||
|
||||
struct ril_sim_info_priv {
|
||||
char *log_prefix;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
char *spn;
|
||||
char *cached_spn;
|
||||
char *sim_spn;
|
||||
char *public_spn;
|
||||
char default_spn[RIL_SIM_DEFAULT_SPN_BUFSIZE];
|
||||
struct ofono_sim *sim;
|
||||
struct ril_sim_info_watch state_watch;
|
||||
struct ril_sim_info_watch iccid_watch;
|
||||
struct ril_sim_info_watch imsi_watch;
|
||||
struct ril_sim_info_watch spn_watch;
|
||||
struct ril_network *network;
|
||||
gulong network_operator_changed_id;
|
||||
gboolean update_imsi_cache;
|
||||
gboolean update_iccid_map;
|
||||
};
|
||||
@@ -80,6 +92,8 @@ G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define DBG_(info,fmt,args...) DBG("%s" fmt, (info)->priv->log_prefix, ##args)
|
||||
|
||||
static void ril_sim_info_signal_emit(struct ril_sim_info *self,
|
||||
enum ril_sim_info_signal id)
|
||||
{
|
||||
@@ -105,7 +119,8 @@ static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim, unsigned int id)
|
||||
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim,
|
||||
unsigned int id)
|
||||
{
|
||||
ofono_sim_remove_spn_watch(sim, &id);
|
||||
}
|
||||
@@ -115,14 +130,34 @@ static void ril_sim_info_update_imsi_cache(struct ril_sim_info *self)
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
|
||||
priv->spn && priv->spn[0]) {
|
||||
priv->cached_spn && priv->cached_spn[0]) {
|
||||
gboolean save = FALSE;
|
||||
const char *store = RIL_SIM_INFO_STORE;
|
||||
GKeyFile *cache = storage_open(priv->imsi, store);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
|
||||
DBG("Updating " STORAGEDIR "/%s/%s", priv->imsi, store);
|
||||
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, priv->spn);
|
||||
storage_close(priv->imsi, store, cache, TRUE);
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
save = TRUE;
|
||||
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, priv->cached_spn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (save) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s/%s",
|
||||
priv->imsi, store);
|
||||
storage_close(priv->imsi, store, cache, TRUE);
|
||||
} else {
|
||||
g_key_file_free(cache);
|
||||
}
|
||||
|
||||
g_free(spn);
|
||||
priv->update_imsi_cache = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -135,11 +170,24 @@ static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
|
||||
priv->imsi && priv->imsi[0]) {
|
||||
const char *store = RIL_SIM_ICCID_MAP;
|
||||
GKeyFile *map = storage_open(NULL, store);
|
||||
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, NULL);
|
||||
|
||||
DBG("Updating " STORAGEDIR "/%s", store);
|
||||
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (g_strcmp0(imsi, priv->imsi)) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s", store);
|
||||
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, priv->imsi);
|
||||
storage_close(NULL, store, map, TRUE);
|
||||
storage_close(NULL, store, map, TRUE);
|
||||
} else {
|
||||
g_key_file_free(map);
|
||||
}
|
||||
|
||||
g_free(imsi);
|
||||
priv->update_iccid_map = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -158,19 +206,112 @@ static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_spn(struct ril_sim_info *self, const char *spn)
|
||||
static void ril_sim_info_update_public_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
const char *spn = priv->sim_spn ? priv->sim_spn :
|
||||
priv->cached_spn ? priv->cached_spn :
|
||||
priv->default_spn;
|
||||
|
||||
if (g_strcmp0(priv->public_spn, spn)) {
|
||||
g_free(priv->public_spn);
|
||||
self->spn = priv->public_spn = g_strdup(spn);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_cached_spn(struct ril_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->spn, spn)) {
|
||||
g_free(priv->spn);
|
||||
self->spn = priv->spn = g_strdup(spn);
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
DBG_(self, "cached spn \"%s\"", spn);
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_sim_spn(struct ril_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->sim_spn, spn)) {
|
||||
g_free(priv->sim_spn);
|
||||
priv->sim_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_set_cached_spn(self, spn);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_default_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
char buf[RIL_SIM_DEFAULT_SPN_BUFSIZE];
|
||||
const char *mcc = NULL;
|
||||
const char *mnc = NULL;
|
||||
|
||||
if (priv->sim &&
|
||||
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
|
||||
mcc = ofono_sim_get_mcc(priv->sim);
|
||||
mnc = ofono_sim_get_mnc(priv->sim);
|
||||
}
|
||||
|
||||
if (mcc && mnc) {
|
||||
snprintf(buf, RIL_SIM_DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
|
||||
buf[RIL_SIM_DEFAULT_SPN_BUFSIZE - 1] = 0;
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
if (strcmp(buf, priv->default_spn)) {
|
||||
strncpy(priv->default_spn, buf, RIL_SIM_DEFAULT_SPN_BUFSIZE);
|
||||
DBG_(self, "default spn \"%s\"", priv->default_spn);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_network_check(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->network && priv->network->operator && priv->sim &&
|
||||
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
|
||||
const char *mcc = ofono_sim_get_mcc(priv->sim);
|
||||
const char *mnc = ofono_sim_get_mnc(priv->sim);
|
||||
const struct ofono_network_operator *op =
|
||||
priv->network->operator;
|
||||
|
||||
if (mcc && mcc[0] && !strcmp(mcc, op->mcc) &&
|
||||
mnc && mnc[0] && !strcmp(mnc, op->mnc)) {
|
||||
|
||||
/*
|
||||
* If EFspn is present then sim_spn should be set
|
||||
* before we get registered with the network.
|
||||
*/
|
||||
DBG_(self, "home network \"%s\"", op->name);
|
||||
if (!priv->sim_spn) {
|
||||
ril_sim_info_set_cached_spn(self, op->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_network_operator_changed(struct ril_network *network,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
@@ -184,18 +325,19 @@ static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
/* Need to update ICCID -> IMSI map */
|
||||
DBG("IMSI changed %s -> %s", priv->imsi, imsi);
|
||||
DBG_(self, "IMSI changed %s -> %s",
|
||||
priv->imsi, imsi);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = imsi;
|
||||
DBG("imsi[%s] = %s", priv->iccid, imsi);
|
||||
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
|
||||
ril_sim_info_update_iccid_map(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
} else if (imsi) {
|
||||
g_free(imsi);
|
||||
} else {
|
||||
DBG("No imsi for iccid %s", priv->iccid);
|
||||
DBG_(self, "no imsi for iccid %s", priv->iccid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,21 +348,22 @@ static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
g_key_file_free(cache);
|
||||
|
||||
if (spn && spn[0] && g_strcmp0(priv->spn, spn)) {
|
||||
if (priv->spn && priv->spn[0]) {
|
||||
if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
|
||||
if (priv->cached_spn && priv->cached_spn[0]) {
|
||||
/* Need to update the cache file */
|
||||
DBG("spn changing %s -> %s", priv->spn, spn);
|
||||
DBG_(self, "spn changing %s -> %s",
|
||||
priv->cached_spn, spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->spn);
|
||||
self->spn = priv->spn = spn;
|
||||
DBG("spn[%s] = \"%s\"", priv->imsi, spn);
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = spn;
|
||||
DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
} else if (spn) {
|
||||
g_free(spn);
|
||||
} else {
|
||||
DBG("No spn for imsi %s", priv->imsi);
|
||||
DBG_(self, "no spn for imsi %s", priv->imsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,7 +385,8 @@ static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
|
||||
static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
DBG("%s", imsi);
|
||||
|
||||
DBG_(watch->info, "%s", imsi);
|
||||
ril_sim_info_set_imsi(watch->info, imsi);
|
||||
}
|
||||
|
||||
@@ -250,14 +394,16 @@ static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
DBG("%s", spn);
|
||||
ril_sim_info_set_spn(watch->info, spn);
|
||||
|
||||
DBG_(watch->info, "%s", spn);
|
||||
ril_sim_info_set_sim_spn(watch->info, spn);
|
||||
}
|
||||
|
||||
static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
DBG("%s", iccid);
|
||||
|
||||
DBG_(watch->info, "%s", iccid);
|
||||
ril_sim_info_set_iccid(watch->info, iccid);
|
||||
}
|
||||
|
||||
@@ -275,7 +421,7 @@ static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
struct ril_sim_info_watch *watch;
|
||||
|
||||
DBG("%d", state);
|
||||
DBG_(self, "%d", state);
|
||||
|
||||
switch (state) {
|
||||
case OFONO_SIM_STATE_READY:
|
||||
@@ -314,6 +460,9 @@ static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
|
||||
ril_sim_info_watch_remove(&priv->iccid_watch);
|
||||
break;
|
||||
}
|
||||
|
||||
ril_sim_info_update_default_spn(self);
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
|
||||
@@ -323,11 +472,12 @@ static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
|
||||
ril_sim_info_handle_sim_state(watch->info, new_state);
|
||||
}
|
||||
|
||||
struct ril_sim_info *ril_sim_info_new(struct ofono_sim *sim)
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix)
|
||||
{
|
||||
struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
|
||||
|
||||
ril_sim_info_set_ofono_sim(self, sim);
|
||||
self->priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -348,7 +498,8 @@ void ril_sim_info_unref(struct ril_sim_info *self)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self, struct ofono_sim *sim)
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
@@ -370,10 +521,36 @@ void ril_sim_info_set_ofono_sim(struct ril_sim_info *self, struct ofono_sim *sim
|
||||
&priv->state_watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(priv->state_watch.id);
|
||||
DBG("Attached to sim");
|
||||
DBG_(self, "attached to sim");
|
||||
ril_sim_info_handle_sim_state(self,
|
||||
ofono_sim_get_state(sim));
|
||||
}
|
||||
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_network(struct ril_sim_info *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (G_LIKELY(self) && self->priv->network != network) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->network) {
|
||||
ril_network_remove_handlers(priv->network,
|
||||
&priv->network_operator_changed_id, 1);
|
||||
ril_network_unref(priv->network);
|
||||
}
|
||||
if (network) {
|
||||
priv->network_operator_changed_id =
|
||||
ril_network_add_operator_changed_handler(network,
|
||||
ril_sim_info_network_operator_changed,
|
||||
self);
|
||||
priv->network = ril_network_ref(network);
|
||||
ril_sim_info_network_check(self);
|
||||
} else {
|
||||
priv->network = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,14 +599,14 @@ static void ril_sim_info_init(struct ril_sim_info *self)
|
||||
RIL_SIMINFO_TYPE, struct ril_sim_info_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_sim_info_watch_init(self, &priv->state_watch, NULL,
|
||||
ofono_sim_remove_state_watch);
|
||||
ril_sim_info_watch_init(self, &priv->iccid_watch, ril_sim_info_set_iccid,
|
||||
ofono_sim_remove_iccid_watch);
|
||||
ril_sim_info_watch_init(self, &priv->imsi_watch, ril_sim_info_set_imsi,
|
||||
ofono_sim_remove_imsi_watch);
|
||||
ril_sim_info_watch_init(self, &priv->spn_watch, ril_sim_info_set_spn,
|
||||
ril_sim_info_remove_spn_watch);
|
||||
ril_sim_info_watch_init(self, &priv->state_watch,
|
||||
NULL, ofono_sim_remove_state_watch);
|
||||
ril_sim_info_watch_init(self, &priv->iccid_watch,
|
||||
ril_sim_info_set_iccid, ofono_sim_remove_iccid_watch);
|
||||
ril_sim_info_watch_init(self, &priv->imsi_watch,
|
||||
ril_sim_info_set_imsi, ofono_sim_remove_imsi_watch);
|
||||
ril_sim_info_watch_init(self, &priv->spn_watch,
|
||||
ril_sim_info_set_sim_spn, ril_sim_info_remove_spn_watch);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dispose(GObject *object)
|
||||
@@ -437,14 +614,30 @@ static void ril_sim_info_dispose(GObject *object)
|
||||
struct ril_sim_info *self = RIL_SIMINFO(object);
|
||||
|
||||
ril_sim_info_set_ofono_sim(self, NULL);
|
||||
ril_sim_info_set_network(self, NULL);
|
||||
G_OBJECT_CLASS(ril_sim_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_sim_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(object);
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
g_free(priv->log_prefix);
|
||||
g_free(priv->cached_spn);
|
||||
g_free(priv->public_spn);
|
||||
GASSERT(!priv->iccid);
|
||||
GASSERT(!priv->imsi);
|
||||
GASSERT(!priv->sim_spn);
|
||||
G_OBJECT_CLASS(ril_sim_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_info_class_init(RilSimInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_sim_info_dispose;
|
||||
object_class->finalize = ril_sim_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_info_priv));
|
||||
NEW_SIGNAL(klass, ICCID);
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
|
||||
@@ -29,10 +29,11 @@ struct ril_sim_info {
|
||||
struct ofono_sim;
|
||||
typedef void (*ril_sim_info_cb_t)(struct ril_sim_info *info, void *arg);
|
||||
|
||||
struct ril_sim_info *ril_sim_info_new(struct ofono_sim *sim);
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix);
|
||||
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *info);
|
||||
void ril_sim_info_unref(struct ril_sim_info *si);
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *si, struct ofono_sim *sim);
|
||||
void ril_sim_info_set_network(struct ril_sim_info *si, struct ril_network *net);
|
||||
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *si,
|
||||
ril_sim_info_cb_t cb, void *arg);
|
||||
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *si,
|
||||
|
||||
@@ -205,7 +205,7 @@ struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
ril_sim_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define TYPE_LOCAL 129
|
||||
#define TYPE_INTERNATIONAL 145
|
||||
|
||||
static unsigned char path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
static unsigned char sim_path[4] = {0x3F, 0x00, 0x7F, 0x10};
|
||||
|
||||
enum ril_sms_events {
|
||||
SMS_EVENT_NEW_SMS,
|
||||
@@ -42,6 +42,7 @@ struct ril_sms {
|
||||
GRilIoQueue *q;
|
||||
struct ril_modem *modem;
|
||||
struct ofono_sms *sms;
|
||||
struct ofono_sim_context *sim_context;
|
||||
gulong event_id[SMS_EVENT_COUNT];
|
||||
guint timer_id;
|
||||
};
|
||||
@@ -366,11 +367,10 @@ static void ril_request_delete_sms_om_sim(struct ril_sms *sd, int record)
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sms_on_sim_cb(const struct ofono_error *error,
|
||||
const unsigned char *sdata,
|
||||
int length, void *data)
|
||||
static void ril_sms_on_sim_cb(int ok, int total_length, int record,
|
||||
const unsigned char *sdata, int length, void *userdata)
|
||||
{
|
||||
struct ril_sms_on_sim_req *cbd = data;
|
||||
struct ril_sms_on_sim_req *cbd = userdata;
|
||||
struct ril_sms *sd = cbd->sd;
|
||||
|
||||
/*
|
||||
@@ -383,7 +383,7 @@ static void ril_sms_on_sim_cb(const struct ofono_error *error,
|
||||
* the read length to take into account this read octet in order
|
||||
* to calculate the proper tpdu length.
|
||||
*/
|
||||
if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
|
||||
if (ok) {
|
||||
unsigned int smsc_len = sdata[1] + 1;
|
||||
ofono_sms_deliver_notify(sd->sms, sdata + 1, length - 1,
|
||||
length - smsc_len - 1);
|
||||
@@ -409,10 +409,15 @@ static void ril_sms_on_sim(GRilIoChannel *io, guint ril_event,
|
||||
grilio_parser_get_int32(&rilp, &data_len) && data_len > 0 &&
|
||||
grilio_parser_get_int32(&rilp, &rec)) {
|
||||
DBG("rec %d", rec);
|
||||
ril_sim_read_file_linear(sim, SIM_EFSMS_FILEID, rec,
|
||||
EFSMS_LENGTH, path, sizeof(path),
|
||||
ril_sms_on_sim_cb,
|
||||
ril_sms_on_sim_req_new(sd,rec));
|
||||
if (sd->sim_context) {
|
||||
ofono_sim_read_record(sd->sim_context,
|
||||
SIM_EFSMS_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
rec, EFSMS_LENGTH,
|
||||
sim_path, sizeof(sim_path),
|
||||
ril_sms_on_sim_cb,
|
||||
ril_sms_on_sim_req_new(sd,rec));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,14 +449,18 @@ static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ofono_sim *sim = ril_modem_ofono_sim(modem);
|
||||
struct ril_sms *sd = g_new0(struct ril_sms, 1);
|
||||
|
||||
sd->modem = modem;
|
||||
sd->sms = sms;
|
||||
sd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
sd->sim_context = ofono_sim_context_create(sim);
|
||||
sd->q = grilio_queue_new(sd->io);
|
||||
sd->timer_id = g_idle_add(ril_sms_register, sd);
|
||||
ofono_sms_set_data(sms, sd);
|
||||
|
||||
GASSERT(sd->sim_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -463,6 +472,10 @@ static void ril_sms_remove(struct ofono_sms *sms)
|
||||
DBG("");
|
||||
ofono_sms_set_data(sms, NULL);
|
||||
|
||||
if (sd->sim_context) {
|
||||
ofono_sim_context_free(sd->sim_context);
|
||||
}
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
|
||||
grilio_channel_remove_handler(sd->io, sd->event_id[i]);
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ struct ofono_sim;
|
||||
#define RIL_RETRY_SECS (2)
|
||||
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
||||
|
||||
struct ril_mce;
|
||||
struct ril_data;
|
||||
struct ril_modem;
|
||||
struct ril_radio;
|
||||
@@ -46,6 +47,7 @@ struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_sim_info;
|
||||
struct ril_sim_settings;
|
||||
struct ril_cell_info;
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
|
||||
@@ -52,13 +52,6 @@ struct ril_voicecall {
|
||||
gulong ecclist_change_id;
|
||||
};
|
||||
|
||||
struct release_id_req {
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_change_state_req {
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
@@ -71,12 +64,6 @@ struct lastcause_req {
|
||||
int id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_req {
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
|
||||
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
|
||||
|
||||
@@ -387,9 +374,12 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
{
|
||||
GASSERT(vd);
|
||||
if (!vd->clcc_poll_id) {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
vd->clcc_poll_id = grilio_queue_send_request_full(vd->q,
|
||||
NULL, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
req, RIL_REQUEST_GET_CURRENT_CALLS,
|
||||
ril_voicecall_clcc_poll_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,9 +437,7 @@ static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall_req *cbd = user_data;
|
||||
struct ofono_voicecall *vc = cbd->vc;
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
if (vd->cb) {
|
||||
@@ -458,11 +446,21 @@ static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
}
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
ofono_error("call failed.");
|
||||
vd->cb = NULL;
|
||||
vd->data = NULL;
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
|
||||
/*
|
||||
* Even though this dial request may have already been
|
||||
* completed (successfully) by ril_voicecall_clcc_poll_cb,
|
||||
* RIL_REQUEST_DIAL may still fail.
|
||||
*/
|
||||
if (vd->cb) {
|
||||
struct ofono_error error;
|
||||
ofono_voicecall_cb_t cb = vd->cb;
|
||||
void *cbdata = vd->data;
|
||||
vd->cb = NULL;
|
||||
vd->data = NULL;
|
||||
cb(ril_error_failure(&error), cbdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,27 +470,22 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
|
||||
void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_req *cbd = g_new(struct ril_voicecall_req, 1);
|
||||
const char *phstr = phone_number_to_string(ph);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("dialing \"%s\"", phstr);
|
||||
|
||||
DBG("%s,%d,0", phstr, clir);
|
||||
cbd->vc = vc;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
|
||||
GASSERT(!vd->cb);
|
||||
vd->cb = cbd->cb;
|
||||
vd->data = cbd->data;
|
||||
vd->cb = cb;
|
||||
vd->data = data;
|
||||
|
||||
grilio_request_append_utf8(req, phstr); /* Number to dial */
|
||||
grilio_request_append_int32(req, clir); /* CLIR mode */
|
||||
grilio_request_append_int32(req, 0); /* UUS information (absent) */
|
||||
|
||||
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_DIAL,
|
||||
ril_voicecall_dial_cb, g_free, cbd);
|
||||
ril_voicecall_dial_cb, NULL, vd);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -836,17 +829,11 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
|
||||
static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
{
|
||||
int i;
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
|
||||
DBG("");
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
|
||||
g_slist_free(vd->calls);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(vd->event_id); i++) {
|
||||
grilio_channel_remove_handler(vd->io, vd->event_id[i]);
|
||||
}
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
if (vd->timer_id > 0) {
|
||||
g_source_remove(vd->timer_id);
|
||||
@@ -855,6 +842,8 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
|
||||
ril_ecclist_unref(vd->ecclist);
|
||||
|
||||
grilio_channel_remove_handlers(vd->io, vd->event_id,
|
||||
G_N_ELEMENTS(vd->event_id));
|
||||
grilio_channel_unref(vd->io);
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
|
||||
@@ -104,6 +104,11 @@ typedef void (*ofono_sim_state_event_cb_t)(enum ofono_sim_state new_state,
|
||||
typedef void (*ofono_sim_file_read_cb_t)(int ok, int total_length, int record,
|
||||
const unsigned char *data,
|
||||
int record_length, void *userdata);
|
||||
|
||||
typedef void (*ofono_sim_read_info_cb_t)(int ok, unsigned char file_status,
|
||||
int total_length, int record_length,
|
||||
void *userdata);
|
||||
|
||||
typedef void (*ofono_sim_file_changed_cb_t)(int id, void *userdata);
|
||||
|
||||
typedef void (*ofono_sim_file_write_cb_t)(int ok, void *userdata);
|
||||
@@ -247,6 +252,22 @@ int ofono_sim_read(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected,
|
||||
ofono_sim_file_read_cb_t cb, void *data);
|
||||
|
||||
int ofono_sim_read_path(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_read_cb_t cb, void *data);
|
||||
|
||||
int ofono_sim_read_info(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
const unsigned char *path, unsigned int pth_len,
|
||||
ofono_sim_read_info_cb_t cb, void *data);
|
||||
|
||||
int ofono_sim_read_record(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
int record, int record_length,
|
||||
const unsigned char *path, unsigned int pth_len,
|
||||
ofono_sim_file_read_cb_t cb, void *data);
|
||||
|
||||
int ofono_sim_write(struct ofono_sim_context *context, int id,
|
||||
ofono_sim_file_write_cb_t cb,
|
||||
enum ofono_sim_file_structure structure, int record,
|
||||
|
||||
@@ -44,6 +44,16 @@
|
||||
|
||||
#include "mbpi.h"
|
||||
|
||||
const char *mbpi_database = MBPI_DATABASE;
|
||||
|
||||
/*
|
||||
* Use IPv4 for MMS contexts because gprs.c assumes that MMS proxy
|
||||
* address is IPv4.
|
||||
*/
|
||||
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
|
||||
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
|
||||
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
|
||||
|
||||
#define _(x) case x: return (#x)
|
||||
|
||||
enum MBPI_ERROR {
|
||||
@@ -111,7 +121,7 @@ static void mbpi_g_set_error(GMarkupParseContext *context, GError **error,
|
||||
|
||||
va_end(ap);
|
||||
|
||||
g_prefix_error(error, "%s:%d ", MBPI_DATABASE, line_number);
|
||||
g_prefix_error(error, "%s:%d ", mbpi_database, line_number);
|
||||
}
|
||||
|
||||
static void text_handler(GMarkupParseContext *context,
|
||||
@@ -166,7 +176,7 @@ static void authentication_start(GMarkupParseContext *context,
|
||||
static void usage_start(GMarkupParseContext *context,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
enum ofono_gprs_context_type *type, GError **error)
|
||||
struct ofono_gprs_provision_data *apn, GError **error)
|
||||
{
|
||||
const char *text = NULL;
|
||||
int i;
|
||||
@@ -182,12 +192,14 @@ static void usage_start(GMarkupParseContext *context,
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(text, "internet") == 0)
|
||||
*type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
|
||||
else if (strcmp(text, "mms") == 0)
|
||||
*type = OFONO_GPRS_CONTEXT_TYPE_MMS;
|
||||
else if (strcmp(text, "wap") == 0)
|
||||
*type = OFONO_GPRS_CONTEXT_TYPE_WAP;
|
||||
if (strcmp(text, "internet") == 0) {
|
||||
apn->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
|
||||
apn->proto = mbpi_default_internet_proto;
|
||||
} else if (strcmp(text, "mms") == 0) {
|
||||
apn->type = OFONO_GPRS_CONTEXT_TYPE_MMS;
|
||||
apn->proto = mbpi_default_mms_proto;
|
||||
} else if (strcmp(text, "wap") == 0)
|
||||
apn->type = OFONO_GPRS_CONTEXT_TYPE_WAP;
|
||||
else
|
||||
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
|
||||
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
|
||||
@@ -220,7 +232,7 @@ static void apn_start(GMarkupParseContext *context, const gchar *element_name,
|
||||
&apn->message_proxy);
|
||||
else if (g_str_equal(element_name, "usage"))
|
||||
usage_start(context, attribute_names, attribute_values,
|
||||
&apn->type, error);
|
||||
apn, error);
|
||||
}
|
||||
|
||||
static void apn_end(GMarkupParseContext *context, const gchar *element_name,
|
||||
@@ -331,7 +343,7 @@ static void apn_handler(GMarkupParseContext *context, struct gsm_data *gsm,
|
||||
|
||||
ap->apn = g_strdup(apn);
|
||||
ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
|
||||
ap->proto = OFONO_GPRS_PROTO_IP;
|
||||
ap->proto = mbpi_default_proto;
|
||||
ap->auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
|
||||
|
||||
g_markup_parse_context_push(context, &apn_parser, ap);
|
||||
@@ -611,11 +623,11 @@ static gboolean mbpi_parse(const GMarkupParser *parser, gpointer userdata,
|
||||
GMarkupParseContext *context;
|
||||
gboolean ret;
|
||||
|
||||
fd = open(MBPI_DATABASE, O_RDONLY);
|
||||
fd = open(mbpi_database, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
g_set_error(error, G_FILE_ERROR,
|
||||
g_file_error_from_errno(errno),
|
||||
"open(%s) failed: %s", MBPI_DATABASE,
|
||||
"open(%s) failed: %s", mbpi_database,
|
||||
g_strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
@@ -624,7 +636,7 @@ static gboolean mbpi_parse(const GMarkupParser *parser, gpointer userdata,
|
||||
close(fd);
|
||||
g_set_error(error, G_FILE_ERROR,
|
||||
g_file_error_from_errno(errno),
|
||||
"fstat(%s) failed: %s", MBPI_DATABASE,
|
||||
"fstat(%s) failed: %s", mbpi_database,
|
||||
g_strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
@@ -634,7 +646,7 @@ static gboolean mbpi_parse(const GMarkupParser *parser, gpointer userdata,
|
||||
close(fd);
|
||||
g_set_error(error, G_FILE_ERROR,
|
||||
g_file_error_from_errno(errno),
|
||||
"mmap(%s) failed: %s", MBPI_DATABASE,
|
||||
"mmap(%s) failed: %s", mbpi_database,
|
||||
g_strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
extern const char *mbpi_database;
|
||||
extern enum ofono_gprs_proto mbpi_default_internet_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_mms_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_proto;
|
||||
|
||||
const char *mbpi_ap_type(enum ofono_gprs_context_type type);
|
||||
|
||||
void mbpi_ap_free(struct ofono_gprs_provision_data *data);
|
||||
|
||||
@@ -53,7 +53,7 @@ enum phonebook_number_type {
|
||||
};
|
||||
|
||||
struct ofono_phonebook {
|
||||
DBusMessage *pending;
|
||||
GSList *pending;
|
||||
int storage_index; /* go through all supported storage */
|
||||
int flags;
|
||||
GString *vcards; /* entries with vcard 3.0 format */
|
||||
@@ -431,9 +431,24 @@ static void export_phonebook_cb(const struct ofono_error *error, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
static void phonebook_reply(gpointer data, gpointer user_data)
|
||||
{
|
||||
DBusMessage *msg = data;
|
||||
struct ofono_phonebook *phonebook = user_data;
|
||||
DBusMessage *reply = generate_export_entries_reply(phonebook, msg);
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
}
|
||||
|
||||
static void phonebook_cancel(gpointer data)
|
||||
{
|
||||
DBusMessage *msg = data;
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, __ofono_error_canceled(msg));
|
||||
}
|
||||
|
||||
static void export_phonebook(struct ofono_phonebook *phonebook)
|
||||
{
|
||||
DBusMessage *reply;
|
||||
const char *pb = storage_support[phonebook->storage_index];
|
||||
|
||||
if (pb) {
|
||||
@@ -442,13 +457,9 @@ static void export_phonebook(struct ofono_phonebook *phonebook)
|
||||
return;
|
||||
}
|
||||
|
||||
reply = generate_export_entries_reply(phonebook, phonebook->pending);
|
||||
if (reply == NULL) {
|
||||
dbus_message_unref(phonebook->pending);
|
||||
return;
|
||||
}
|
||||
|
||||
__ofono_dbus_pending_reply(&phonebook->pending, reply);
|
||||
g_slist_foreach(phonebook->pending, phonebook_reply, phonebook);
|
||||
g_slist_free(phonebook->pending);
|
||||
phonebook->pending = NULL;
|
||||
phonebook->flags |= PHONEBOOK_FLAG_CACHED;
|
||||
}
|
||||
|
||||
@@ -458,23 +469,22 @@ static DBusMessage *import_entries(DBusConnection *conn, DBusMessage *msg,
|
||||
struct ofono_phonebook *phonebook = data;
|
||||
DBusMessage *reply;
|
||||
|
||||
if (phonebook->pending) {
|
||||
reply = __ofono_error_busy(phonebook->pending);
|
||||
g_dbus_send_message(conn, reply);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (phonebook->flags & PHONEBOOK_FLAG_CACHED) {
|
||||
reply = generate_export_entries_reply(phonebook, msg);
|
||||
g_dbus_send_message(conn, reply);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_string_set_size(phonebook->vcards, 0);
|
||||
phonebook->storage_index = 0;
|
||||
|
||||
phonebook->pending = dbus_message_ref(msg);
|
||||
export_phonebook(phonebook);
|
||||
if (phonebook->pending) {
|
||||
phonebook->pending = g_slist_append(phonebook->pending,
|
||||
dbus_message_ref(msg));
|
||||
} else {
|
||||
phonebook->pending = g_slist_append(NULL,
|
||||
dbus_message_ref(msg));
|
||||
g_string_set_size(phonebook->vcards, 0);
|
||||
phonebook->storage_index = 0;
|
||||
export_phonebook(phonebook);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -516,6 +526,11 @@ static void phonebook_unregister(struct ofono_atom *atom)
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(pb->atom);
|
||||
|
||||
if (pb->pending) {
|
||||
g_slist_free_full(pb->pending, phonebook_cancel);
|
||||
pb->pending = NULL;
|
||||
}
|
||||
|
||||
ofono_modem_remove_interface(modem, OFONO_PHONEBOOK_INTERFACE);
|
||||
g_dbus_unregister_interface(conn, path, OFONO_PHONEBOOK_INTERFACE);
|
||||
}
|
||||
|
||||
@@ -1710,7 +1710,7 @@ static gboolean check_bdn_status(struct ofono_sim *sim)
|
||||
if (sim_sst_is_active(sim->efsst, sim->efsst_length,
|
||||
SIM_SST_SERVICE_BDN)) {
|
||||
sim_fs_read_info(sim->context, SIM_EFBDN_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED, NULL, 0,
|
||||
sim_efbdn_info_read_cb, sim);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1764,7 +1764,7 @@ static void sim_efsst_read_cb(int ok, int length, int record,
|
||||
if (sim_sst_is_active(sim->efsst, sim->efsst_length,
|
||||
SIM_SST_SERVICE_FDN)) {
|
||||
sim_fs_read_info(sim->context, SIM_EFADN_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED, NULL, 0,
|
||||
sim_efadn_info_read_cb, sim);
|
||||
return;
|
||||
}
|
||||
@@ -2314,6 +2314,34 @@ int ofono_sim_read(struct ofono_sim_context *context, int id,
|
||||
return sim_fs_read(context, id, expected_type, 0, 0, NULL, 0, cb, data);
|
||||
}
|
||||
|
||||
int ofono_sim_read_path(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_read_cb_t cb, void *data)
|
||||
{
|
||||
return sim_fs_read(context, id, expected_type, 0, 0,
|
||||
path, path_len, cb, data);
|
||||
}
|
||||
|
||||
int ofono_sim_read_info(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
const unsigned char *path, unsigned int pth_len,
|
||||
ofono_sim_read_info_cb_t cb, void *data)
|
||||
{
|
||||
return sim_fs_read_info(context, id, expected_type, path, pth_len,
|
||||
cb, data);
|
||||
}
|
||||
|
||||
int ofono_sim_read_record(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
int record, int record_length,
|
||||
const unsigned char *path, unsigned int pth_len,
|
||||
ofono_sim_file_read_cb_t cb, void *data)
|
||||
{
|
||||
return sim_fs_read_record(context, id, expected_type, record,
|
||||
record_length, path, pth_len, cb, data);
|
||||
}
|
||||
|
||||
int ofono_sim_write(struct ofono_sim_context *context, int id,
|
||||
ofono_sim_file_write_cb_t cb,
|
||||
enum ofono_sim_file_structure structure, int record,
|
||||
|
||||
@@ -264,7 +264,7 @@ static void sim_fs_op_error(struct sim_fs *fs)
|
||||
}
|
||||
|
||||
if (op->info_only == TRUE)
|
||||
((sim_fs_read_info_cb_t) op->cb)
|
||||
((ofono_sim_read_info_cb_t) op->cb)
|
||||
(0, 0, 0, 0, op->userdata);
|
||||
else if (op->is_read == TRUE)
|
||||
((ofono_sim_file_read_cb_t) op->cb)
|
||||
@@ -335,6 +335,27 @@ static void sim_fs_op_write_cb(const struct ofono_error *error, void *data)
|
||||
sim_fs_end_current(fs);
|
||||
}
|
||||
|
||||
static void sim_fs_op_read_record_cb(const struct ofono_error *error,
|
||||
const unsigned char *sdata, int length,
|
||||
void *data)
|
||||
{
|
||||
struct sim_fs *fs = data;
|
||||
struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
|
||||
ofono_sim_file_read_cb_t cb = op->cb;
|
||||
|
||||
if (cb == NULL) {
|
||||
sim_fs_end_current(fs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
|
||||
cb(1, -1, op->current, sdata, length, op->userdata);
|
||||
else
|
||||
cb(0, -1, op->current, NULL, 0, op->userdata);
|
||||
|
||||
sim_fs_end_current(fs);
|
||||
}
|
||||
|
||||
static void sim_fs_op_read_block_cb(const struct ofono_error *error,
|
||||
const unsigned char *data, int len,
|
||||
void *user)
|
||||
@@ -565,7 +586,8 @@ static gboolean sim_fs_op_read_record(gpointer user)
|
||||
|
||||
driver->read_file_linear(fs->sim, op->id, op->current,
|
||||
op->record_length,
|
||||
NULL, 0,
|
||||
op->path_len ? op->path : NULL,
|
||||
op->path_len,
|
||||
sim_fs_op_retrieve_cb, fs);
|
||||
break;
|
||||
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
|
||||
@@ -576,7 +598,8 @@ static gboolean sim_fs_op_read_record(gpointer user)
|
||||
|
||||
driver->read_file_cyclic(fs->sim, op->id, op->current,
|
||||
op->record_length,
|
||||
NULL, 0,
|
||||
op->path_len ? op->path : NULL,
|
||||
op->path_len,
|
||||
sim_fs_op_retrieve_cb, fs);
|
||||
break;
|
||||
default:
|
||||
@@ -700,7 +723,7 @@ static void sim_fs_op_info_cb(const struct ofono_error *error, int length,
|
||||
* It's an info-only request, so there is no need to request
|
||||
* actual contents of the EF. Just return the EF-info.
|
||||
*/
|
||||
sim_fs_read_info_cb_t cb = op->cb;
|
||||
ofono_sim_read_info_cb_t cb = op->cb;
|
||||
|
||||
cb(1, file_status, op->length,
|
||||
op->record_length, op->userdata);
|
||||
@@ -778,7 +801,7 @@ static gboolean sim_fs_op_check_cached(struct sim_fs *fs)
|
||||
* It's an info-only request, so there is no need to request
|
||||
* actual contents of the EF. Just return the EF-info.
|
||||
*/
|
||||
sim_fs_read_info_cb_t cb = op->cb;
|
||||
ofono_sim_read_info_cb_t cb = op->cb;
|
||||
|
||||
cb(1, file_status, op->length,
|
||||
op->record_length, op->userdata);
|
||||
@@ -820,7 +843,28 @@ static gboolean sim_fs_op_next(gpointer user_data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (op->is_read == TRUE) {
|
||||
if (op->is_read == TRUE && op->current > 0) {
|
||||
switch (op->structure) {
|
||||
case OFONO_SIM_FILE_STRUCTURE_FIXED:
|
||||
driver->read_file_linear(fs->sim, op->id,
|
||||
op->current, op->record_length,
|
||||
op->path_len ? op->path : NULL,
|
||||
op->path_len,
|
||||
sim_fs_op_read_record_cb, fs);
|
||||
break;
|
||||
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
|
||||
driver->read_file_cyclic(fs->sim, op->id,
|
||||
op->current, op->record_length,
|
||||
op->path_len ? op->path : NULL,
|
||||
op->path_len,
|
||||
sim_fs_op_read_record_cb, fs);
|
||||
break;
|
||||
case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
|
||||
default:
|
||||
ofono_error("Wrong file structure for reading record");
|
||||
break;
|
||||
}
|
||||
} else if (op->is_read == TRUE) {
|
||||
if (sim_fs_op_check_cached(fs))
|
||||
return FALSE;
|
||||
|
||||
@@ -859,7 +903,8 @@ static gboolean sim_fs_op_next(gpointer user_data)
|
||||
|
||||
int sim_fs_read_info(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
sim_fs_read_info_cb_t cb, void *data)
|
||||
const unsigned char *path, unsigned int pth_len,
|
||||
ofono_sim_read_info_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_fs *fs = context->fs;
|
||||
struct sim_fs_op *op;
|
||||
@@ -887,6 +932,8 @@ int sim_fs_read_info(struct ofono_sim_context *context, int id,
|
||||
op->is_read = TRUE;
|
||||
op->info_only = TRUE;
|
||||
op->context = context;
|
||||
memcpy(op->path, path, pth_len);
|
||||
op->path_len = pth_len;
|
||||
|
||||
g_queue_push_tail(fs->op_q, op);
|
||||
|
||||
@@ -943,6 +990,59 @@ int sim_fs_read(struct ofono_sim_context *context, int id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sim_fs_read_record(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
int record, int record_length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_file_read_cb_t cb, void *data)
|
||||
{
|
||||
struct sim_fs *fs = context->fs;
|
||||
struct sim_fs_op *op;
|
||||
|
||||
if (cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (fs->driver == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (record < 1)
|
||||
return -EINVAL;
|
||||
|
||||
if ((expected_type == OFONO_SIM_FILE_STRUCTURE_FIXED &&
|
||||
fs->driver->read_file_linear == NULL) ||
|
||||
(expected_type == OFONO_SIM_FILE_STRUCTURE_CYCLIC &&
|
||||
fs->driver->read_file_cyclic == NULL)) {
|
||||
cb(0, 0, 0, NULL, 0, data);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (fs->op_q == NULL)
|
||||
fs->op_q = g_queue_new();
|
||||
|
||||
op = g_try_new0(struct sim_fs_op, 1);
|
||||
if (op == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
op->id = id;
|
||||
op->structure = expected_type;
|
||||
op->cb = cb;
|
||||
op->userdata = data;
|
||||
op->is_read = TRUE;
|
||||
op->info_only = FALSE;
|
||||
op->context = context;
|
||||
op->record_length = record_length;
|
||||
op->current = record;
|
||||
memcpy(op->path, path, path_len);
|
||||
op->path_len = path_len;
|
||||
|
||||
g_queue_push_tail(fs->op_q, op);
|
||||
|
||||
if (g_queue_get_length(fs->op_q) == 1)
|
||||
fs->op_source = g_idle_add(sim_fs_op_next, fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sim_fs_write(struct ofono_sim_context *context, int id,
|
||||
ofono_sim_file_write_cb_t cb,
|
||||
enum ofono_sim_file_structure structure, int record,
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
|
||||
struct sim_fs;
|
||||
|
||||
typedef void (*sim_fs_read_info_cb_t)(int ok, unsigned char file_status,
|
||||
int total_length, int record_length,
|
||||
void *userdata);
|
||||
|
||||
struct sim_fs *sim_fs_new(struct ofono_sim *sim,
|
||||
const struct ofono_sim_driver *driver);
|
||||
struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs);
|
||||
@@ -45,9 +41,16 @@ int sim_fs_read(struct ofono_sim_context *context, int id,
|
||||
const unsigned char *path, unsigned int len,
|
||||
ofono_sim_file_read_cb_t cb, void *data);
|
||||
|
||||
int sim_fs_read_record(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
int record, int record_length,
|
||||
const unsigned char *path, unsigned int len,
|
||||
ofono_sim_file_read_cb_t cb, void *data);
|
||||
|
||||
int sim_fs_read_info(struct ofono_sim_context *context, int id,
|
||||
enum ofono_sim_file_structure expected_type,
|
||||
sim_fs_read_info_cb_t cb, void *data);
|
||||
const unsigned char *path, unsigned int pth_len,
|
||||
ofono_sim_read_info_cb_t cb, void *data);
|
||||
|
||||
void sim_fs_check_version(struct sim_fs *fs);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Source: %{name}-%{version}.tar.bz2
|
||||
Requires: dbus
|
||||
Requires: systemd
|
||||
Requires: ofono-configs
|
||||
Requires: libgrilio >= 1.0.6
|
||||
Requires: libgrilio >= 1.0.8
|
||||
Requires: libglibutil >= 1.0.6
|
||||
Requires(preun): systemd
|
||||
Requires(post): systemd
|
||||
@@ -21,7 +21,7 @@ BuildRequires: pkgconfig(libudev) >= 145
|
||||
BuildRequires: pkgconfig(bluez) >= 4.85
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
BuildRequires: pkgconfig(libwspcodec) >= 2.0
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.6
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.8
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.6
|
||||
BuildRequires: libtool
|
||||
BuildRequires: automake
|
||||
|
||||
Reference in New Issue
Block a user