* [PATCH 1/2] qmimodem: implement call-barring driver
2024-02-15 7:17 [0/2] qmimodem: add more drivers Ivaylo Dimitrov
@ 2024-02-15 7:17 ` Ivaylo Dimitrov
2024-02-15 20:43 ` Denis Kenzior
2024-02-15 7:17 ` [PATCH 2/2] qmimodem: implement call-forwarding driver Ivaylo Dimitrov
1 sibling, 1 reply; 8+ messages in thread
From: Ivaylo Dimitrov @ 2024-02-15 7:17 UTC (permalink / raw)
To: ofono; +Cc: denkenz, absicsz, merlijn, Ivaylo Dimitrov
---
Makefile.am | 3 +-
drivers/qmimodem/call-barring.c | 264 ++++++++++++++++++++++++++++++++++++++++
drivers/qmimodem/qmi.c | 1 +
drivers/qmimodem/voice.h | 2 +
plugins/gobi.c | 2 +
5 files changed, 271 insertions(+), 1 deletion(-)
create mode 100644 drivers/qmimodem/call-barring.c
diff --git a/Makefile.am b/Makefile.am
index d8766e0..98f41e0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -387,7 +387,8 @@ builtin_sources += $(qmi_sources) \
drivers/qmimodem/radio-settings.c \
drivers/qmimodem/location-reporting.c \
drivers/qmimodem/netmon.c \
- drivers/qmimodem/call-settings.c
+ drivers/qmimodem/call-settings.c \
+ drivers/qmimodem/call-barring.c
builtin_modules += gobi
builtin_sources += plugins/gobi.c
diff --git a/drivers/qmimodem/call-barring.c b/drivers/qmimodem/call-barring.c
new file mode 100644
index 0000000..dc84026
--- /dev/null
+++ b/drivers/qmimodem/call-barring.c
@@ -0,0 +1,264 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2024 Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-barring.h>
+
+#include "qmi.h"
+#include "voice.h"
+#include "util.h"
+
+struct call_barring_data {
+ struct qmi_service *voice;
+};
+
+static uint8_t lock_code_to_reason(const char *lock)
+{
+ if (!strcmp(lock, "AO"))
+ return QMI_VOICE_SS_RSN_ALL_OUTGOING;
+ else if (!strcmp(lock, "OI"))
+ return QMI_VOICE_SS_RSN_OUT_INT;
+ else if (!strcmp(lock, "OX"))
+ return QMI_VOICE_SS_RSN_OUT_INT_EXT_TO_HOME;
+ else if (!strcmp(lock, "AI"))
+ return QMI_VOICE_SS_RSN_ALL_IN;
+ else if (!strcmp(lock, "IR"))
+ return QMI_VOICE_SS_RSN_IN_ROAMING;
+ else if (!strcmp(lock, "AB"))
+ return QMI_VOICE_SS_RSN_BAR_ALL;
+ else if (!strcmp(lock, "AG"))
+ return QMI_VOICE_SS_RSN_BAR_ALL_OUTGOING;
+ else if (!strcmp(lock, "AC"))
+ return QMI_VOICE_SS_RSN_BAR_ALL_IN;
+ else {
+ DBG("Unknown lock code %s", lock);
+ return 0;
+ }
+}
+
+static void set_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_call_barring_set_cb_t cb = cbd->cb;
+ uint16_t error;
+
+ DBG("");
+
+ if (!qmi_result_set_error(result, &error))
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ else {
+ /* Check for invalid password error */
+ if (error != 92 ||
+ !qmi_result_get_uint16(result, 0x10, &error) ||
+ error != 129)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ else
+ CALLBACK_WITH_CME_ERROR(cb, 16, cbd->data);
+ }
+}
+
+static void qmi_set(struct ofono_call_barring *barr, const char *lock,
+ int enable, const char *passwd, int cls,
+ ofono_call_barring_set_cb_t cb, void *data)
+{
+ struct call_barring_data *bd = ofono_call_barring_get_data(barr);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ struct qmi_param *param;
+ struct __attribute__((__packed__)) {
+ uint8_t service;
+ uint8_t reason;
+ } ssd;
+
+ DBG("");
+
+ ssd.reason = lock_code_to_reason(lock);
+
+ if (!bd || !ssd.reason)
+ goto error;
+
+ ssd.service = enable ? QMI_VOICE_SS_ACTION_ACTIVATE :
+ QMI_VOICE_SS_ACTION_DEACTIVATE;
+
+ param = qmi_param_new();
+ qmi_param_append(param, 0x01, sizeof(ssd), &ssd);
+
+ if (cls != 7 /* BEARER_CLASS_DEFAULT */)
+ qmi_param_append_uint8(param, 0x10, cls);
+
+ qmi_param_append(param, 0x11, 4, passwd);
+
+ if (qmi_service_send(bd->voice, QMI_VOICE_SET_SUPS_SERVICE, param,
+ set_cb, cbd, g_free) > 0)
+ return;
+
+ qmi_param_free(param);
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void query_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_call_barring_query_cb_t cb = cbd->cb;
+ uint8_t mask;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, NULL) ||
+ !qmi_result_get_uint8(result, 0x10, &mask)) {
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+ return;
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+}
+
+static void qmi_query(struct ofono_call_barring *barr, const char *lock,
+ int cls, ofono_call_barring_query_cb_t cb, void *data)
+{
+ struct call_barring_data *bd = ofono_call_barring_get_data(barr);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ struct qmi_param *param;
+ uint8_t reason = lock_code_to_reason(lock);
+
+ DBG("");
+
+ if (!bd || !reason)
+ goto error;
+
+ param = qmi_param_new();
+ qmi_param_append_uint8(param, 0x01, reason);
+
+ if (cls != 7 /* BEARER_CLASS_DEFAULT */)
+ qmi_param_append_uint8(param, 0x10, cls);
+
+ if (qmi_service_send(bd->voice, QMI_VOICE_GET_CALL_BARRING, param,
+ query_cb, cbd, g_free) > 0)
+ return;
+
+ qmi_param_free(param);
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static void qmi_set_passwd(struct ofono_call_barring *barr, const char *lock,
+ const char *old_passwd, const char *new_passwd,
+ ofono_call_barring_set_cb_t cb, void *data)
+{
+ struct call_barring_data *bd = ofono_call_barring_get_data(barr);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ struct qmi_param *param;
+ struct __attribute__((__packed__)) {
+ uint8_t reason;
+ uint8_t old_passwd[4];
+ uint8_t new_passwd[4];
+ uint8_t new_passwd_rpt[4];
+ } ssd;
+
+ DBG("");
+
+ if (!bd)
+ goto error;
+
+ ssd.reason = lock_code_to_reason(lock);
+ memcpy(&ssd.old_passwd, old_passwd, 4);
+ memcpy(&ssd.new_passwd, new_passwd, 4);
+ memcpy(&ssd.new_passwd_rpt, new_passwd, 4);
+
+ param = qmi_param_new();
+
+ qmi_param_append(param, 0x01, sizeof(ssd), &ssd);
+
+ if (qmi_service_send(bd->voice, QMI_VOICE_SET_CALL_BARRING_PWD, param,
+ set_cb, cbd, g_free) > 0)
+ return;
+
+ qmi_param_free(param);
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void create_voice_cb(struct qmi_service *service, void *user_data)
+{
+ struct ofono_call_barring *barr = user_data;
+ struct call_barring_data *bd = ofono_call_barring_get_data(barr);
+
+ DBG("");
+
+ if (!service) {
+ ofono_error("Failed to request Voice service");
+ ofono_call_barring_remove(barr);
+ return;
+ }
+
+ bd->voice = qmi_service_ref(service);
+
+ ofono_call_barring_register(barr);
+}
+
+static int qmi_call_barring_probe(struct ofono_call_barring *barr,
+ unsigned int vendor, void *user_data)
+{
+ struct qmi_device *device = user_data;
+ struct call_barring_data *bd;
+
+ DBG("");
+
+ bd = g_new0(struct call_barring_data, 1);
+
+ ofono_call_barring_set_data(barr, bd);
+
+ qmi_service_create_shared(device, QMI_SERVICE_VOICE,
+ create_voice_cb, barr, NULL);
+
+ return 0;
+}
+
+static void qmi_call_barring_remove(struct ofono_call_barring *barr)
+{
+ struct call_barring_data *bd = ofono_call_barring_get_data(barr);
+
+ DBG("");
+
+ ofono_call_barring_set_data(barr, NULL);
+
+ if (bd->voice)
+ qmi_service_unref(bd->voice);
+
+ g_free(bd);
+}
+
+static const struct ofono_call_barring_driver driver = {
+ .probe = qmi_call_barring_probe,
+ .remove = qmi_call_barring_remove,
+ .set = qmi_set,
+ .query = qmi_query,
+ .set_passwd = qmi_set_passwd
+};
+
+OFONO_ATOM_DRIVER_BUILTIN(call_barring, qmimodem, &driver)
diff --git a/drivers/qmimodem/qmi.c b/drivers/qmimodem/qmi.c
index fe663ec..7f0d605 100644
--- a/drivers/qmimodem/qmi.c
+++ b/drivers/qmimodem/qmi.c
@@ -466,6 +466,7 @@ static const struct {
{ 0x0053, "HARDWARE_RESTRICTED" },
{ 0x0054, "ACK_NOT_SENT" },
{ 0x0055, "INJECT_TIMEOUT" },
+ { 0x005c, "SUPS_FAILURE_CAUSE" },
{ }
};
diff --git a/drivers/qmimodem/voice.h b/drivers/qmimodem/voice.h
index 7755d2e..472d724 100644
--- a/drivers/qmimodem/voice.h
+++ b/drivers/qmimodem/voice.h
@@ -51,8 +51,10 @@ enum voice_commands {
QMI_VOICE_SUPS_NOTIFICATION_IND = 0x32,
QMI_VOICE_SET_SUPS_SERVICE = 0x33,
QMI_VOICE_GET_CALL_WAITING = 0x34,
+ QMI_VOICE_GET_CALL_BARRING = 0x35,
QMI_VOICE_GET_CLIP = 0x36,
QMI_VOICE_GET_CLIR = 0x37,
+ QMI_VOICE_SET_CALL_BARRING_PWD = 0x39,
QMI_VOICE_CANCEL_USSD = 0x3c,
QMI_VOICE_USSD_RELEASE_IND = 0x3d,
QMI_VOICE_USSD_IND = 0x3e,
diff --git a/plugins/gobi.c b/plugins/gobi.c
index a550016..a7ef552 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -33,6 +33,7 @@
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/modem.h>
+#include <ofono/call-barring.h>
#include <ofono/call-settings.h>
#include <ofono/devinfo.h>
#include <ofono/netreg.h>
@@ -757,6 +758,7 @@ static void gobi_post_online(struct ofono_modem *modem)
if (data->features & GOBI_VOICE) {
ofono_ussd_create(modem, 0, "qmimodem", data->device);
ofono_call_settings_create(modem, 0, "qmimodem", data->device);
+ ofono_call_barring_create(modem, 0, "qmimodem", data->device);
}
}
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] qmimodem: implement call-forwarding driver
2024-02-15 7:17 [0/2] qmimodem: add more drivers Ivaylo Dimitrov
2024-02-15 7:17 ` [PATCH 1/2] qmimodem: implement call-barring driver Ivaylo Dimitrov
@ 2024-02-15 7:17 ` Ivaylo Dimitrov
2024-02-15 20:46 ` Denis Kenzior
1 sibling, 1 reply; 8+ messages in thread
From: Ivaylo Dimitrov @ 2024-02-15 7:17 UTC (permalink / raw)
To: ofono; +Cc: denkenz, absicsz, merlijn, Ivaylo Dimitrov
---
Makefile.am | 3 +-
drivers/qmimodem/call-forwarding.c | 352 +++++++++++++++++++++++++++++++++++++
drivers/qmimodem/voice.h | 1 +
plugins/gobi.c | 3 +
4 files changed, 358 insertions(+), 1 deletion(-)
create mode 100644 drivers/qmimodem/call-forwarding.c
diff --git a/Makefile.am b/Makefile.am
index 98f41e0..77df87a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -388,7 +388,8 @@ builtin_sources += $(qmi_sources) \
drivers/qmimodem/location-reporting.c \
drivers/qmimodem/netmon.c \
drivers/qmimodem/call-settings.c \
- drivers/qmimodem/call-barring.c
+ drivers/qmimodem/call-barring.c \
+ drivers/qmimodem/call-forwarding.c
builtin_modules += gobi
builtin_sources += plugins/gobi.c
diff --git a/drivers/qmimodem/call-forwarding.c b/drivers/qmimodem/call-forwarding.c
new file mode 100644
index 0000000..45f25ae
--- /dev/null
+++ b/drivers/qmimodem/call-forwarding.c
@@ -0,0 +1,352 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2024 Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-forwarding.h>
+
+#include "qmi.h"
+#include "voice.h"
+#include "util.h"
+
+struct call_forwarding_data {
+ struct qmi_service *voice;
+};
+
+struct call_forwarding_info_ext {
+ uint8_t active;
+ uint8_t cls;
+ uint8_t time;
+ uint8_t pind;
+ uint8_t sind;
+ uint8_t type;
+ uint8_t plan;
+ uint8_t len;
+ uint8_t number[0];
+};
+
+static int forw_type_to_reason(int type)
+{
+ switch (type) {
+ case 0:
+ return QMI_VOICE_SS_RSN_FWD_UNCONDITIONAL;
+ case 1:
+ return QMI_VOICE_SS_RSN_FWD_MOBILE_BUSY;
+ case 2:
+ return QMI_VOICE_SS_RSN_FWD_NO_REPLY;
+ case 3:
+ return QMI_VOICE_SS_RSN_FWD_UNREACHABLE;
+ case 4:
+ return QMI_VOICE_SS_RSN_FWD_ALL;
+ case 5:
+ return QMI_VOICE_SS_RSN_FWD_ALL_CONDITIONAL;
+ default:
+ DBG("Unknown forwarding type %d", type);
+ return 0;
+ }
+}
+
+static void set_fwd_cond(struct ofono_call_forwarding_condition *cond,
+ int status, int cls, int time, int type,
+ uint8_t *number, uint8_t nlen)
+{
+ uint8_t maxlen = OFONO_MAX_PHONE_NUMBER_LENGTH;
+
+ cond->status = status;
+ cond->cls = cls;
+ cond->time = time;
+ cond->phone_number.type = type;
+
+ if (nlen < maxlen)
+ maxlen = nlen;
+
+ memcpy(&cond->phone_number.number, number, maxlen);
+ cond->phone_number.number[maxlen] = 0;
+}
+
+static void query_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_call_forwarding_query_cb_t cb = cbd->cb;
+ const uint8_t *p;
+ uint8_t num;
+ uint16_t length;
+
+ DBG("");
+
+ if (qmi_result_set_error(result, NULL))
+ goto error;
+
+ /*
+ * we want extended info, because of the number type.
+ * FIXME - shall we fallback to 0x10 if there is no extended info?
+ */
+ p = qmi_result_get(result, 0x16, &length);
+ if (p) {
+ struct ofono_call_forwarding_condition *list;
+ const uint8_t *end = p + length;
+ int i;
+
+ num = *p++;
+
+ list = g_new0(struct ofono_call_forwarding_condition, num);
+
+ for (i = 0; i < num; i++) {
+ struct call_forwarding_info_ext *info = (void *)p;
+ int type;
+
+ /* do not try to access beyond buffer end */
+ if (p + sizeof(*info) > end ||
+ p + sizeof(*info) + info->len > end) {
+ g_free(list);
+ goto error;
+ }
+
+ if (info->type == 1)
+ type = OFONO_NUMBER_TYPE_INTERNATIONAL;
+ else
+ type = OFONO_NUMBER_TYPE_UNKNOWN;
+
+ set_fwd_cond(&list[i], info->active, info->cls,
+ info->time, type, info->number,
+ info->len);
+ p += sizeof(*info) + info->len;
+ }
+
+ CALLBACK_WITH_SUCCESS(cb, num, list, cbd->data);
+ g_free(list);
+ return;
+ }
+
+error:
+ CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+}
+
+static void qmi_query(struct ofono_call_forwarding *cf, int type, int cls,
+ ofono_call_forwarding_query_cb_t cb, void *data)
+{
+ struct call_forwarding_data *cfd = ofono_call_forwarding_get_data(cf);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ struct qmi_param *param;
+ uint8_t reason = forw_type_to_reason(type);
+
+ DBG("");
+
+ if (!cfd || !reason)
+ goto error;
+
+ param = qmi_param_new();
+ qmi_param_append_uint8(param, 0x01, reason);
+
+ if (cls != 7 /* BEARER_CLASS_DEFAULT */)
+ qmi_param_append_uint8(param, 0x10, cls);
+
+ if (qmi_service_send(cfd->voice, QMI_VOICE_GET_CALL_FWDING, param,
+ query_cb, cbd, g_free) > 0)
+ return;
+
+ qmi_param_free(param);
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
+}
+
+static void set_cb(struct qmi_result *result, void *user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_call_forwarding_set_cb_t cb = cbd->cb;
+
+ DBG("");
+
+ if (!qmi_result_set_error(result, NULL))
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ else
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void qmi_register(struct ofono_call_forwarding *cf, int type, int cls,
+ const struct ofono_phone_number *ph, int time,
+ ofono_call_forwarding_set_cb_t cb, void *data)
+{
+ struct call_forwarding_data *cfd = ofono_call_forwarding_get_data(cf);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ struct qmi_param *param;
+ struct __attribute__((__packed__)) {
+ uint8_t service;
+ uint8_t reason;
+ } ssd;
+ struct __attribute__((__packed__)) {
+ uint8_t type;
+ uint8_t plan;
+ } tpd;
+
+ DBG("");
+
+ ssd.reason = forw_type_to_reason(type);
+
+ if (!cfd || !ssd.reason)
+ goto error;
+
+ ssd.service = QMI_VOICE_SS_ACTION_REGISTER;
+
+ param = qmi_param_new();
+ qmi_param_append(param, 0x01, sizeof(ssd), &ssd);
+
+ if (cls != 7 /* BEARER_CLASS_DEFAULT */)
+ qmi_param_append_uint8(param, 0x10, cls);
+
+ qmi_param_append(param, 0x12, strlen(ph->number), ph->number);
+ qmi_param_append_uint8(param, 0x13, time);
+
+ tpd.type = ph->type == OFONO_NUMBER_TYPE_INTERNATIONAL ? 1 : 0;
+ tpd.plan = tpd.type;
+ qmi_param_append(param, 0x14, sizeof(tpd), &tpd);
+
+ if (qmi_service_send(cfd->voice, QMI_VOICE_SET_SUPS_SERVICE, param,
+ set_cb, cbd, g_free) > 0)
+ return;
+
+ qmi_param_free(param);
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void qmi_set(struct ofono_call_forwarding *cf, int type, int cls,
+ int service, ofono_call_forwarding_set_cb_t cb,
+ void *data)
+{
+ struct call_forwarding_data *cfd = ofono_call_forwarding_get_data(cf);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ struct qmi_param *param;
+ struct __attribute__((__packed__)) {
+ uint8_t service;
+ uint8_t reason;
+ } ssd;
+
+ DBG("");
+
+ ssd.reason = forw_type_to_reason(type);
+
+ if (!cfd || !ssd.reason)
+ goto error;
+
+ ssd.service = service;
+
+ param = qmi_param_new();
+ qmi_param_append(param, 0x01, sizeof(ssd), &ssd);
+
+ if (cls != 7 /* BEARER_CLASS_DEFAULT */)
+ qmi_param_append_uint8(param, 0x10, cls);
+
+ if (qmi_service_send(cfd->voice, QMI_VOICE_SET_SUPS_SERVICE, param,
+ set_cb, cbd, g_free) > 0)
+ return;
+
+ qmi_param_free(param);
+
+error:
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void qmi_activate(struct ofono_call_forwarding *cf, int type, int cls,
+ ofono_call_forwarding_set_cb_t cb, void *data)
+{
+ qmi_set(cf, type, cls, QMI_VOICE_SS_ACTION_ACTIVATE, cb, data);
+}
+
+static void qmi_deactivate(struct ofono_call_forwarding *cf, int type, int cls,
+ ofono_call_forwarding_set_cb_t cb, void *data)
+{
+ qmi_set(cf, type, cls, QMI_VOICE_SS_ACTION_DEACTIVATE, cb, data);
+}
+
+static void qmi_erase(struct ofono_call_forwarding *cf, int type, int cls,
+ ofono_call_forwarding_set_cb_t cb, void *data)
+{
+ qmi_set(cf, type, cls, QMI_VOICE_SS_ACTION_ERASE, cb, data);
+}
+
+static void create_voice_cb(struct qmi_service *service, void *user_data)
+{
+ struct ofono_call_forwarding *cf = user_data;
+ struct call_forwarding_data *cfd = ofono_call_forwarding_get_data(cf);
+
+ DBG("");
+
+ if (!service) {
+ ofono_error("Failed to request Voice service");
+ ofono_call_forwarding_remove(cf);
+ return;
+ }
+
+ cfd->voice = qmi_service_ref(service);
+
+ ofono_call_forwarding_register(cf);
+}
+
+static int qmi_call_forwarding_probe(struct ofono_call_forwarding *cf,
+ unsigned int vendor, void *user_data)
+{
+ struct qmi_device *device = user_data;
+ struct call_forwarding_data *cfd;
+
+ DBG("");
+
+ cfd = g_new0(struct call_forwarding_data, 1);
+
+ ofono_call_forwarding_set_data(cf, cfd);
+
+ qmi_service_create_shared(device, QMI_SERVICE_VOICE,
+ create_voice_cb, cf, NULL);
+
+ return 0;
+}
+
+static void qmi_call_forwarding_remove(struct ofono_call_forwarding *cf)
+{
+ struct call_forwarding_data *cfd = ofono_call_forwarding_get_data(cf);
+
+ DBG("");
+
+ ofono_call_forwarding_set_data(cf, NULL);
+
+ if (cfd->voice)
+ qmi_service_unref(cfd->voice);
+
+ g_free(cfd);
+}
+
+static const struct ofono_call_forwarding_driver driver = {
+ .probe = qmi_call_forwarding_probe,
+ .remove = qmi_call_forwarding_remove,
+ .registration = qmi_register,
+ .activation = qmi_activate,
+ .query = qmi_query,
+ .deactivation = qmi_deactivate,
+ .erasure = qmi_erase
+};
+
+OFONO_ATOM_DRIVER_BUILTIN(call_forwarding, qmimodem, &driver)
diff --git a/drivers/qmimodem/voice.h b/drivers/qmimodem/voice.h
index 472d724..12c87be 100644
--- a/drivers/qmimodem/voice.h
+++ b/drivers/qmimodem/voice.h
@@ -54,6 +54,7 @@ enum voice_commands {
QMI_VOICE_GET_CALL_BARRING = 0x35,
QMI_VOICE_GET_CLIP = 0x36,
QMI_VOICE_GET_CLIR = 0x37,
+ QMI_VOICE_GET_CALL_FWDING = 0x38,
QMI_VOICE_SET_CALL_BARRING_PWD = 0x39,
QMI_VOICE_CANCEL_USSD = 0x3c,
QMI_VOICE_USSD_RELEASE_IND = 0x3d,
diff --git a/plugins/gobi.c b/plugins/gobi.c
index a7ef552..e98a07b 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -34,6 +34,7 @@
#include <ofono/plugin.h>
#include <ofono/modem.h>
#include <ofono/call-barring.h>
+#include <ofono/call-forwarding.h>
#include <ofono/call-settings.h>
#include <ofono/devinfo.h>
#include <ofono/netreg.h>
@@ -759,6 +760,8 @@ static void gobi_post_online(struct ofono_modem *modem)
ofono_ussd_create(modem, 0, "qmimodem", data->device);
ofono_call_settings_create(modem, 0, "qmimodem", data->device);
ofono_call_barring_create(modem, 0, "qmimodem", data->device);
+ ofono_call_forwarding_create(modem, 0, "qmimodem",
+ data->device);
}
}
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread