summaryrefslogtreecommitdiffstats
path: root/qmi-client.c
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-09-06 00:19:36 +0200
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-09-06 00:19:36 +0200
commitf35a9bbd1ebb52433f313c675fbe01bb1ca96d7d (patch)
treec1aff224fd4a2ea2e5e06805c7caff5406b0ab42 /qmi-client.c
parent06cf4fe68ad096961b4b9c653ba2bc31d270f009 (diff)
downloadi9305_modem-master.zip
i9305_modem-master.tar.gz
i9305_modem-master.tar.bz2
initial version of QMI-RILHEADmaster
The RIL uses libqmi. qmicli and ModemManager were used as references for using libqmi. The request processing is modelled after Samsung-RIL and a lot of code could be reused for QMI-RIL. Establishing a data connection succeeds and mobile data is working in early testing. However, there is not yet a routine for handling interruptions and notifying Android about them. Information about the serving network including signal strength are retrieved and an unlocked SIM card is recognized. Reading data from the SIM and requesting the usual device information should work as well. Support for voice calls and SMS is completely missing at this point. Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
Diffstat (limited to 'qmi-client.c')
-rw-r--r--qmi-client.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/qmi-client.c b/qmi-client.c
new file mode 100644
index 0000000..ab47325
--- /dev/null
+++ b/qmi-client.c
@@ -0,0 +1,347 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ *
+ * QMI-RIL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QMI-RIL 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 QMI-RIL. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+#include <telephony/ril.h>
+
+#include <gio/gio.h>
+
+#include <qmi-ril.h>
+
+#define CDC_PATH "/dev/cdc-wdm2"
+
+static GCancellable *cancellable;
+static GFile *file;
+static QmiDevice *device;
+
+QmiService qmi_services[] = {
+ QMI_SERVICE_DMS,
+ QMI_SERVICE_NAS,
+ QMI_SERVICE_UIM,
+ QMI_SERVICE_WDS,
+ QMI_SERVICE_WDA,
+};
+
+unsigned int qmi_service_count = sizeof(qmi_services)
+ / sizeof(QmiService);
+unsigned int qmi_indications_count = 3;
+
+static unsigned int qmi_client_count = 0;
+static unsigned int qmi_client_failures = 0;
+static unsigned int qmi_indications_ready = 0;
+
+static void all_indications_ready()
+{
+ if (qmi_indications_ready < qmi_indications_count) {
+ RIL_LOGD("%d indications ready", qmi_indications_ready);
+ return;
+ } else {
+ RIL_LOGD("registered indications");
+ // initialization finished, main loop can now process
+ // requests
+ ril_radio_state_update(RADIO_STATE_OFF);
+ }
+}
+
+static void nas_set_event_report_ready(QmiClientNas *client,
+ GAsyncResult *res)
+{
+ QmiMessageNasSetEventReportOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_nas_set_event_report_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s\n", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_nas_set_event_report_output_get_result(output, &error)) {
+ RIL_LOGE("Couldn't set nas event report: %s", error->message);
+ g_error_free(error);
+ qmi_message_nas_set_event_report_output_unref(output);
+
+ return;
+ }
+
+ qmi_message_nas_set_event_report_output_unref(output);
+
+ ctx->nas_event_report_indication_id =
+ g_signal_connect(ctx->NasClient, "event-report",
+ G_CALLBACK(nas_event_report_indication_cb),
+ NULL);
+
+ qmi_indications_ready++;
+ all_indications_ready();
+}
+
+static void nas_register_indications_ready(QmiClientNas *client,
+ GAsyncResult *res)
+{
+ QmiMessageNasRegisterIndicationsOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_nas_register_indications_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_nas_register_indications_output_get_result(output, &error)) {
+ RIL_LOGE("Couldn't register nas indications: %s", error->message);
+ g_error_free(error);
+ qmi_message_nas_register_indications_output_unref(output);
+
+ return;
+ }
+
+ qmi_message_nas_register_indications_output_unref(output);
+
+ ctx->serving_system_indication_id =
+ g_signal_connect(ctx->NasClient, "serving-system",
+ G_CALLBACK(serving_system_indication_cb),
+ NULL);
+
+ qmi_indications_ready++;
+ all_indications_ready();
+}
+
+static void dms_set_event_report_ready(QmiClientDms *client,
+ GAsyncResult *res)
+{
+ QmiMessageDmsSetEventReportOutput *output;
+ GError *error = NULL;
+
+ output = qmi_client_dms_set_event_report_finish(client, res, &error);
+
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (!qmi_message_dms_set_event_report_output_get_result(output, &error)) {
+ RIL_LOGE("Couldn't set dms event report: %s", error->message);
+ g_error_free(error);
+ qmi_message_dms_set_event_report_output_unref(output);
+ return;
+ }
+
+ qmi_message_dms_set_event_report_output_unref(output);
+
+ ctx->dms_event_report_indication_id = g_signal_connect(
+ ctx->DmsClient,
+ "event-report",
+ G_CALLBACK(dms_event_report_indication_cb),
+ NULL);
+
+ qmi_indications_ready++;
+ all_indications_ready();
+}
+
+static void setup_indications()
+{
+ QmiMessageDmsSetEventReportInput *dms_event_report_input;
+ QmiMessageNasRegisterIndicationsInput *nas_register_input;
+ QmiMessageNasSetEventReportInput *nas_event_report_input;
+ static const gint8 thresholds_data[] = {-80, -40, 0, 40, 80};
+ GArray *thresholds;
+
+ dms_event_report_input = qmi_message_dms_set_event_report_input_new();
+ qmi_message_dms_set_event_report_input_set_operating_mode_reporting(
+ dms_event_report_input, TRUE, NULL);
+ qmi_client_dms_set_event_report(ctx->DmsClient,
+ dms_event_report_input, 5, NULL,
+ (GAsyncReadyCallback)dms_set_event_report_ready,
+ NULL);
+ qmi_message_dms_set_event_report_input_unref(dms_event_report_input);
+
+ nas_register_input = qmi_message_nas_register_indications_input_new();
+ qmi_message_nas_register_indications_input_set_serving_system_events(
+ nas_register_input, TRUE, NULL);
+ qmi_client_nas_register_indications(ctx->NasClient,
+ nas_register_input, 5, NULL,
+ (GAsyncReadyCallback)nas_register_indications_ready,
+ NULL);
+ qmi_message_nas_register_indications_input_unref(nas_register_input);
+
+ nas_event_report_input = qmi_message_nas_set_event_report_input_new();
+ thresholds = g_array_sized_new(FALSE, FALSE, sizeof (gint8),
+ G_N_ELEMENTS(thresholds_data));
+ g_array_append_vals(thresholds, thresholds_data,
+ G_N_ELEMENTS(thresholds_data));
+ qmi_message_nas_set_event_report_input_set_signal_strength_indicator(
+ nas_event_report_input, TRUE, thresholds, NULL);
+ g_array_unref(thresholds);
+ qmi_client_nas_set_event_report(ctx->NasClient,
+ nas_event_report_input, 5, NULL,
+ (GAsyncReadyCallback)nas_set_event_report_ready,
+ NULL);
+ qmi_message_nas_set_event_report_input_unref(nas_event_report_input);
+}
+
+static void allocate_client_ready(QmiDevice *dev, GAsyncResult *res)
+{
+ QmiClient *client;
+ QmiService service;
+ GError *error = NULL;
+
+ client = qmi_device_allocate_client_finish(dev, res, &error);
+ if (!client) {
+ RIL_LOGE("%s: error: couldn't create client: %s", __func__,
+ error->message);
+ qmi_client_failures++;
+ RIL_LOGE("increased failure counter to %d", qmi_client_failures);
+ return;
+ }
+
+ service = qmi_client_get_service(client);
+
+ switch (service) {
+ case QMI_SERVICE_DMS:
+ ctx->DmsClient = g_object_ref(QMI_CLIENT_DMS(client));
+ break;
+ case QMI_SERVICE_NAS:
+ ctx->NasClient = g_object_ref(QMI_CLIENT_NAS(client));
+ break;
+ case QMI_SERVICE_UIM:
+ ctx->UimClient = g_object_ref(QMI_CLIENT_UIM(client));
+ break;
+ case QMI_SERVICE_WDS:
+ ctx->WdsClient = g_object_ref(QMI_CLIENT_WDS(client));
+ break;
+ case QMI_SERVICE_WDA:
+ ctx->WdaClient = g_object_ref(QMI_CLIENT_WDA(client));
+ // configure it right away
+ qmi_set_raw_ip_mode();
+ break;
+ default:
+ RIL_LOGE("unknown service");
+ return;
+ }
+
+ RIL_LOGD("QMI client for service %s allocated",
+ qmi_service_get_string(service));
+ RIL_LOGD("%d of %d clients allocated", qmi_client_count,
+ qmi_service_count);
+
+ qmi_client_count++;
+
+ if (qmi_client_failures)
+ RIL_LOGD("%d failures", qmi_client_failures);
+
+ if (qmi_client_count == qmi_service_count)
+ setup_indications();
+}
+
+static void device_allocate_client(QmiDevice *dev)
+{
+ guint8 cid = QMI_CID_NONE;
+ unsigned int i;
+
+ ctx = g_slice_new(Context);
+ ctx->file = g_object_ref(file);
+ ctx->device = g_object_ref(device);
+ if (cancellable)
+ ctx->cancellable = g_object_ref(cancellable);
+
+ for (i = 0; i < qmi_service_count; i++)
+ qmi_device_allocate_client(dev, qmi_services[i], cid,
+ 10, cancellable,
+ (GAsyncReadyCallback)allocate_client_ready,
+ NULL);
+
+ RIL_LOGD("Started allocating QMI clients");
+}
+
+static void device_open_ready(QmiDevice *dev, GAsyncResult *res)
+{
+ GError *error = NULL;
+
+ if (!qmi_device_open_finish(dev, res, &error)) {
+ RIL_LOGE("error: couldn't open the QmiDevice: %s",
+ error->message);
+ qmi_client_failures++;
+ return;
+ }
+
+ RIL_LOGD("QMI Device at '%s' ready",
+ qmi_device_get_path_display(dev));
+
+ device_allocate_client(dev);
+}
+
+static void device_new_ready(GObject *unused, GAsyncResult *res)
+{
+ QmiDeviceOpenFlags open_flags = QMI_DEVICE_OPEN_FLAGS_NONE;
+ GError *error = NULL;
+
+ device = qmi_device_new_finish(res, &error);
+ if (!device) {
+ RIL_LOGE("error: couldn't create QmiDevice: %s",
+ error->message);
+ qmi_client_failures++;
+ return;
+ }
+
+ open_flags |= QMI_DEVICE_OPEN_FLAGS_AUTO;
+
+ /* Open the device */
+ qmi_device_open(device, open_flags, 15, cancellable,
+ (GAsyncReadyCallback)device_open_ready, NULL);
+}
+
+int create_qmi_clients(void)
+{
+ cancellable = g_cancellable_new();
+
+ file = g_file_new_for_path(CDC_PATH);
+
+ if(g_file_query_exists(file, NULL))
+ qmi_device_new(file, cancellable,
+ (GAsyncReadyCallback)device_new_ready,
+ NULL);
+ else {
+ RIL_LOGE("error opening file path");
+ return -1;
+ }
+
+ RIL_LOGD("started creating QMI clients");
+
+ return 0;
+}
+
+int all_clients_running(void)
+{
+ if (qmi_client_failures) {
+ return -1;
+ } else if (qmi_client_count < qmi_service_count
+ || qmi_indications_ready < qmi_indications_count
+ || ril_data->data_connection.raw_ip_mode == FALSE)
+ return 0;
+ else
+ return 1;
+}