diff options
-rw-r--r-- | src/mm-broadband-modem-mbim.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c index 58657750..4d5d8409 100644 --- a/src/mm-broadband-modem-mbim.c +++ b/src/mm-broadband-modem-mbim.c @@ -40,6 +40,7 @@ #include "mm-iface-modem-location.h" #include "mm-iface-modem-messaging.h" #include "mm-iface-modem-signal.h" +#include "mm-iface-modem-sar.h" #include "mm-sms-part-3gpp.h" #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED @@ -54,6 +55,7 @@ static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd static void iface_modem_location_init (MMIfaceModemLocation *iface); static void iface_modem_messaging_init (MMIfaceModemMessaging *iface); static void iface_modem_signal_init (MMIfaceModemSignal *iface); +static void iface_modem_sar_init (MMIfaceModemSar *iface); #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED static void shared_qmi_init (MMSharedQmi *iface); #endif @@ -71,6 +73,7 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbim, mm_broadband_modem_mbim, MM_TYPE_B G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init) G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SAR, iface_modem_sar_init) #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_QMI, shared_qmi_init) #endif @@ -120,6 +123,7 @@ struct _MMBroadbandModemMbimPrivate { gboolean is_atds_signal_supported; gboolean is_intel_reset_supported; gboolean is_slot_info_status_supported; + gboolean is_ms_sar_supported; /* Process unsolicited notifications */ guint notification_id; @@ -2291,6 +2295,16 @@ query_device_services_ready (MbimDevice *device, continue; } + if (service == MBIM_SERVICE_MS_SAR) { + for (j = 0; j < device_services[i]->cids_count; j++) { + if (device_services[i]->cids[j] == MBIM_CID_MS_SAR_CONFIG) { + mm_obj_dbg (self, "SAR is supported"); + self->priv->is_ms_sar_supported = TRUE; + } + } + continue; + } + /* no optional features to check in remaining services */ } mbim_device_service_element_array_free (device_services); @@ -6204,7 +6218,339 @@ messaging_create_sms (MMIfaceModemMessaging *self) } /*****************************************************************************/ +/* Check support (SAR interface) */ + +static gboolean +sar_check_support_finish (MMIfaceModemSar *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +sar_check_support (MMIfaceModemSar *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + mm_obj_dbg (self, "SAR capabilities %s",self->priv->is_ms_sar_supported ? "supported" : "not supported"); + g_task_return_boolean (task, self->priv->is_ms_sar_supported); + g_object_unref (task); +} + +/*****************************************************************************/ + +static gboolean +sar_load_state_finish (MMIfaceModemSar *self, + GAsyncResult *res, + gboolean *out_state, + GError **error) +{ + GError *inner_error = NULL; + gboolean result; + + result = g_task_propagate_boolean (G_TASK (res), &inner_error); + if (inner_error) { + g_propagate_error (error, inner_error); + return FALSE; + } + + if (out_state) + *out_state = result; + return TRUE; +} + +static void +sar_config_query_state_ready (MbimDevice *device, + GAsyncResult *res, + GTask *task) +{ + MbimMessage *response; + GError *error = NULL; + MbimSarBackoffState state; + + response = mbim_device_command_finish (device, res, &error); + if (response && + mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) && + mbim_message_ms_sar_config_response_parse ( + response, + NULL, + &state, + NULL, + NULL, + NULL, + &error)) { + g_task_return_boolean (task, state); + } else + g_task_return_error (task, error); + + g_object_unref (task); + + if (response) + mbim_message_unref (response); +} + +static void +sar_load_state (MMIfaceModemSar *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + MbimDevice *device; + MbimMessage *message; + GTask *task; + + if (!peek_device (self, &device, callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + message = mbim_message_ms_sar_config_query_new (NULL); + mbim_device_command (device, + message, + 10, + NULL, + (GAsyncReadyCallback)sar_config_query_state_ready, + task); + mbim_message_unref (message); +} + +/*****************************************************************************/ + +static gboolean +sar_load_power_level_finish (MMIfaceModemSar *self, + GAsyncResult *res, + guint *out_power_level, + GError **error) +{ + gssize result; + + result = g_task_propagate_int(G_TASK (res), error); + if (result < 0) + return FALSE; + + *out_power_level = (guint) result; + return TRUE; +} + +static void +sar_config_query_power_level_ready (MbimDevice *device, + GAsyncResult *res, + GTask *task) +{ + MbimMessage *response; + GError *error = NULL; + guint32 states_count; + MbimSarConfigStateArray *config_states = NULL; + + response = mbim_device_command_finish (device, res, &error); + if (response && + mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) && + mbim_message_ms_sar_config_response_parse ( + response, + NULL, + NULL, + NULL, + &states_count, + &config_states, + &error)) { + MMBroadbandModemMbim *self; + + self = g_task_get_source_object (task); + if (states_count == 0) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, "Couldn't load config states"); + } else { + if (states_count > 1) + mm_obj_warn (self, "The count of config states is %d, We're just taking the state reported for the first antenna.", states_count); + g_task_return_int (task, config_states[0]->backoff_index); + } + + mbim_sar_config_state_array_free (config_states); + } else + g_task_return_error (task, error); + + g_object_unref (task); + + if (response) + mbim_message_unref (response); +} + +static void +sar_load_power_level (MMIfaceModemSar *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + MbimDevice *device; + MbimMessage *message; + GTask *task; + + if (!peek_device (self, &device, callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + message = mbim_message_ms_sar_config_query_new (NULL); + mbim_device_command (device, + message, + 10, + NULL, + (GAsyncReadyCallback)sar_config_query_power_level_ready, + task); + mbim_message_unref (message); +} + +/*****************************************************************************/ + +static gboolean +sar_enable_finish (MMIfaceModemSar *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +sar_config_set_enable_ready (MbimDevice *device, + GAsyncResult *res, + GTask *task) +{ + MbimMessage *response; + GError *error = NULL; + + response = mbim_device_command_finish (device, res, &error); + if (response && + mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { + g_task_return_boolean (task, TRUE); + } else + g_task_return_error (task, error); + + g_object_unref (task); + if (response) + mbim_message_unref (response); +} + +static void +sar_enable (MMIfaceModemSar *_self, + gboolean enable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + MbimDevice *device; + MbimMessage *message; + GTask *task; + /* + * the value 0xFFFFFFFF means all antennas + * the backoff index set to the current index of modem + */ + MbimSarConfigState state = { + .antenna_index = 0xFFFFFFFF, + .backoff_index = mm_iface_modem_sar_get_power_level(_self) + }; + const MbimSarConfigState* states[] = { &state }; + + if (!peek_device (self, &device, callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + message = mbim_message_ms_sar_config_set_new (MBIM_SAR_CONTROL_MODE_OS, + enable ? MBIM_SAR_BACKOFF_STATE_ENABLED : MBIM_SAR_BACKOFF_STATE_DISABLED, + G_N_ELEMENTS (states), states, NULL); + + mbim_device_command (device, + message, + 10, + NULL, + (GAsyncReadyCallback)sar_config_set_enable_ready, + task); + mbim_message_unref (message); +} + +/*****************************************************************************/ + +static gboolean +sar_set_power_level_finish (MMIfaceModemSar *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +sar_config_set_power_level_ready (MbimDevice *device, + GAsyncResult *res, + GTask *task) +{ + MbimMessage *response; + GError *error = NULL; + + response = mbim_device_command_finish (device, res, &error); + if (response && + mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { + g_task_return_boolean (task, TRUE); + } else + g_task_return_error (task, error); + + g_object_unref (task); + + if (response) + mbim_message_unref (response); +} + + +static void +sar_set_power_level (MMIfaceModemSar *_self, + guint power_level, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + MbimDevice *device; + MbimMessage *message; + GTask *task; + MbimSarConfigState state = { + .antenna_index = 0xFFFFFFFF, + .backoff_index = power_level + }; + const MbimSarConfigState* states[] = { &state }; + + if (!peek_device (self, &device, callback, user_data)) + return; + + if (!mm_iface_modem_get_sar_state (_self)) { + g_task_report_new_error (self, + callback, + user_data, + sar_set_power_level, + MM_CORE_ERROR, + MM_CORE_ERROR_WRONG_STATE, + "Couldn't set power level of SAR, because the SAR is disabled"); + return; + } + + task = g_task_new (self, NULL, callback, user_data); + + message = mbim_message_ms_sar_config_set_new (MBIM_SAR_CONTROL_MODE_OS, + MBIM_SAR_BACKOFF_STATE_ENABLED, + G_N_ELEMENTS (states), states, NULL); + mbim_device_command (device, + message, + 10, + NULL, + (GAsyncReadyCallback)sar_config_set_power_level_ready, + task); + mbim_message_unref (message); +} + +/*****************************************************************************/ static void set_property (GObject *object, @@ -7130,6 +7476,21 @@ iface_modem_signal_init (MMIfaceModemSignal *iface) iface->load_values_finish = modem_signal_load_values_finish; } +static void +iface_modem_sar_init (MMIfaceModemSar *iface) +{ + iface->check_support = sar_check_support; + iface->check_support_finish = sar_check_support_finish; + iface->load_state = sar_load_state; + iface->load_state_finish = sar_load_state_finish; + iface->load_power_level = sar_load_power_level; + iface->load_power_level_finish = sar_load_power_level_finish; + iface->enable = sar_enable; + iface->enable_finish = sar_enable_finish; + iface->set_power_level = sar_set_power_level; + iface->set_power_level_finish = sar_set_power_level_finish; +} + #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED static MMIfaceModemLocation * |