summaryrefslogtreecommitdiffstats
path: root/drivers/rilmodem/ussd.c
diff options
context:
space:
mode:
authorTony Espy <espy@canonical.com>2015-10-13 18:07:53 +0200
committerDenis Kenzior <denkenz@gmail.com>2015-10-13 17:38:45 -0500
commite918a6b222ace2ae034b6b2a2474bda457dfc619 (patch)
tree3e41881b1cb212e7f3102276027c9e5a5320eae2 /drivers/rilmodem/ussd.c
parent9c2af753c0ca7e344019e33911bc590f35f81b12 (diff)
downloadofono-e918a6b222ace2ae034b6b2a2474bda457dfc619.tar.bz2
rilmodem: driver for Android modems
Driver for modems that are accessed through the Android Radio Interface Layer (RIL) for telephony, using the gril library. The driver is almost feature complete with some exceptions, being CBS and SAT the most prominent. Co-authored-by: Tony Espy <espy@canonical.com> Co-authored-by: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com> Co-authored-by: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com> Co-authored-by: Islam Amer <islam.amer@jollamobile.com> Co-authored-by: Jussi Kangas <jussi.kangas@tieto.com> Co-authored-by: Juho Hämäläinen <juho.hamalainen@tieto.com> Co-authored-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com> Co-authored-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com> Co-authored-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com> Co-authored-by: Miia Leinonen <miia.leinonen@oss.tieto.com> Co-authored-by: Martti Piirainen <martti.piirainen@canonical.com> Co-authored-by: You-Sheng Yang <vicamo.yang@canonical.com>
Diffstat (limited to 'drivers/rilmodem/ussd.c')
-rw-r--r--drivers/rilmodem/ussd.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/drivers/rilmodem/ussd.c b/drivers/rilmodem/ussd.c
new file mode 100644
index 00000000..04985ec7
--- /dev/null
+++ b/drivers/rilmodem/ussd.c
@@ -0,0 +1,264 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2013 Jolla Ltd
+ * Copyright (C) 2013 Canonical 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.
+ *
+ * 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
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/ussd.h>
+#include <smsutil.h>
+#include <util.h>
+
+#include "gril.h"
+#include "grilutil.h"
+#include "grilrequest.h"
+#include "grilunsol.h"
+
+#include "rilmodem.h"
+
+#include "ril_constants.h"
+
+struct ussd_data {
+ GRil *ril;
+};
+
+static gboolean request_success(gpointer data)
+{
+ struct cb_data *cbd = data;
+ ofono_ussd_cb_t cb = cbd->cb;
+
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ g_free(cbd);
+
+ return FALSE;
+}
+
+static void ril_ussd_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_ussd *ussd = user_data;
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+
+ /*
+ * We fake an ON_USSD event if there was an error sending the request,
+ * as core will be waiting for one to respond to the Initiate() call.
+ * Note that we already made the callback (see ril_ussd_request()).
+ */
+ if (message->error == RIL_E_SUCCESS)
+ g_ril_print_response_no_args(ud->ril, message);
+ else
+ ofono_ussd_notify(ussd, OFONO_USSD_STATUS_NOT_SUPPORTED,
+ 0, NULL, 0);
+}
+
+static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
+ const unsigned char *pdu, int len,
+ ofono_ussd_cb_t cb, void *data)
+{
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+ struct cb_data *cbd = cb_data_new(cb, data, ussd);
+ enum sms_charset charset;
+ char *text = NULL;
+ int ret = 0;
+
+ if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
+
+ if (charset == SMS_CHARSET_7BIT) {
+ long written;
+
+ text = (char *) unpack_7bit(pdu, len, 0, TRUE,
+ 0, &written, 1);
+ if (text != NULL)
+ *(text + written) = '\0';
+
+ } else if (charset == SMS_CHARSET_UCS2) {
+ text = g_convert((char *) pdu, len,
+ "UTF-8//TRANSLIT", "UCS-2BE",
+ NULL, NULL, NULL);
+ } else {
+ ofono_error("%s: No support for charset %d",
+ __func__, charset);
+ }
+ }
+
+ if (text) {
+ struct parcel rilp;
+
+ g_ril_request_send_ussd(ud->ril, text, &rilp);
+
+ ret = g_ril_send(ud->ril, RIL_REQUEST_SEND_USSD,
+ &rilp, ril_ussd_cb, ussd, NULL);
+ g_free(text);
+ }
+
+ /*
+ * We do not wait for the SEND_USSD reply to do the callback, as some
+ * networks send it after sending one or more ON_USSD events. From the
+ * ofono core perspective, Initiate() does not return until one ON_USSD
+ * event is received: making here a successful callback just makes the
+ * core wait for that event.
+ */
+ if (ret <= 0) {
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, data);
+ } else {
+ g_idle_add(request_success, cbd);
+ }
+}
+
+static void ril_ussd_cancel_cb(struct ril_msg *message, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_ussd *ussd = cbd->user;
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+ ofono_ussd_cb_t cb = cbd->cb;
+
+ if (message->error == RIL_E_SUCCESS) {
+ g_ril_print_response_no_args(ud->ril, message);
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ } else {
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ }
+}
+
+static void ril_ussd_cancel(struct ofono_ussd *ussd,
+ ofono_ussd_cb_t cb, void *user_data)
+{
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+ struct cb_data *cbd = cb_data_new(cb, user_data, ussd);
+ int ret;
+
+ ret = g_ril_send(ud->ril, RIL_REQUEST_CANCEL_USSD, NULL,
+ ril_ussd_cancel_cb, cbd, g_free);
+
+ if (ret <= 0) {
+ g_free(cbd);
+ CALLBACK_WITH_FAILURE(cb, user_data);
+ }
+}
+
+static void ril_ussd_notify(struct ril_msg *message, gpointer user_data)
+{
+ struct ofono_ussd *ussd = user_data;
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+ struct unsol_ussd *unsol;
+
+ unsol = g_ril_unsol_parse_ussd(ud->ril, message);
+ if (unsol == NULL) {
+ ofono_error("%s: Parsing error", __func__);
+ return;
+ }
+
+ /* To fix bug in MTK: USSD-Notify arrive with type 2 instead of 0 */
+ if (g_ril_vendor(ud->ril) == OFONO_RIL_VENDOR_MTK &&
+ unsol->message != NULL && unsol->type == 2)
+ unsol->type = 0;
+
+ /*
+ * With data coding scheme 0x48, we are saying that the ussd string is a
+ * UCS-2 string, uncompressed, and with unspecified message class. For
+ * the DCS coding, see 3gpp 23.038, sect. 5.
+ */
+ if (unsol->message != NULL) {
+ gsize written;
+ char *ucs2;
+
+ ucs2 = g_convert(unsol->message, -1, "UCS-2BE//TRANSLIT",
+ "UTF-8", NULL, &written, NULL);
+ if (ucs2 != NULL) {
+ ofono_ussd_notify(ussd, unsol->type, 0x48,
+ (unsigned char *) ucs2, written);
+ g_free(ucs2);
+ } else {
+ ofono_error("%s: Error transcoding", __func__);
+ }
+ } else {
+ ofono_ussd_notify(ussd, unsol->type, 0, NULL, 0);
+ }
+
+ g_ril_unsol_free_ussd(unsol);
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+ struct ofono_ussd *ussd = user_data;
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+
+ DBG("");
+
+ ofono_ussd_register(ussd);
+
+ /* Register for USSD responses */
+ g_ril_register(ud->ril, RIL_UNSOL_ON_USSD, ril_ussd_notify, ussd);
+
+ return FALSE;
+}
+
+static int ril_ussd_probe(struct ofono_ussd *ussd,
+ unsigned int vendor,
+ void *user)
+{
+ GRil *ril = user;
+ struct ussd_data *ud = g_new0(struct ussd_data, 1);
+
+ ud->ril = g_ril_clone(ril);
+ ofono_ussd_set_data(ussd, ud);
+ g_idle_add(ril_delayed_register, ussd);
+
+ return 0;
+}
+
+static void ril_ussd_remove(struct ofono_ussd *ussd)
+{
+ struct ussd_data *ud = ofono_ussd_get_data(ussd);
+ ofono_ussd_set_data(ussd, NULL);
+
+ g_ril_unref(ud->ril);
+ g_free(ud);
+}
+
+static struct ofono_ussd_driver driver = {
+ .name = RILMODEM,
+ .probe = ril_ussd_probe,
+ .remove = ril_ussd_remove,
+ .request = ril_ussd_request,
+ .cancel = ril_ussd_cancel
+};
+
+void ril_ussd_init(void)
+{
+ ofono_ussd_driver_register(&driver);
+}
+
+void ril_ussd_exit(void)
+{
+ ofono_ussd_driver_unregister(&driver);
+}