diff options
author | Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com> | 2024-02-15 09:17:46 +0200 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2024-02-15 14:31:49 -0600 |
commit | a6119e6b2594e4721219484512a5cc413828116c (patch) | |
tree | c83d68108e19eb36df9d9d3e616ee9b1718adda6 | |
parent | 8af8136f61742be963b67b88f18e85c12509e0f9 (diff) | |
download | ofono-a6119e6b2594e4721219484512a5cc413828116c.tar.gz |
qmimodem: implement call-barring driver
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | drivers/qmimodem/call-barring.c | 264 | ||||
-rw-r--r-- | drivers/qmimodem/qmi.c | 1 | ||||
-rw-r--r-- | drivers/qmimodem/voice.h | 2 | ||||
-rw-r--r-- | plugins/gobi.c | 2 |
5 files changed, 271 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index d8766e08a..98f41e089 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 000000000..dc84026a6 --- /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 fe663ec8c..7f0d60544 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 7755d2e07..a3452c0e4 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 a55001660..a7ef55234 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); } } |