/* * This file is part of QMI-RIL. * * Copyright (C) 2017 Wolfgang Wiedmeyer * * 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 . */ #include #define LOG_TAG "RIL" #include #include #include #include #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; }