diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-09-06 00:19:36 +0200 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-09-06 00:19:36 +0200 |
commit | f35a9bbd1ebb52433f313c675fbe01bb1ca96d7d (patch) | |
tree | c1aff224fd4a2ea2e5e06805c7caff5406b0ab42 /qmi-client.c | |
parent | 06cf4fe68ad096961b4b9c653ba2bc31d270f009 (diff) | |
download | i9305_modem-master.zip i9305_modem-master.tar.gz i9305_modem-master.tar.bz2 |
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.c | 347 |
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; +} |