| /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| /* |
| * This program 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 2 of the License, or |
| * (at your option) any later version. |
| * |
| * 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: |
| * |
| * Copyright (C) 2012 Google, Inc. |
| */ |
| |
| #include <ModemManager.h> |
| #define _LIBMM_INSIDE_MM |
| #include <libmm-glib.h> |
| |
| #include "mm-iface-modem.h" |
| #include "mm-iface-modem-firmware.h" |
| #include "mm-error-helpers.h" |
| #include "mm-log-object.h" |
| |
| #if defined WITH_QMI |
| # include "mm-broadband-modem-qmi.h" |
| #endif |
| #if defined WITH_MBIM |
| # include "mm-broadband-modem-mbim.h" |
| #endif |
| |
| G_DEFINE_INTERFACE (MMIfaceModemFirmware, mm_iface_modem_firmware, MM_TYPE_IFACE_MODEM) |
| |
| /*****************************************************************************/ |
| |
| void |
| mm_iface_modem_firmware_bind_simple_status (MMIfaceModemFirmware *self, |
| MMSimpleStatus *status) |
| { |
| } |
| |
| /*****************************************************************************/ |
| /* Load update settings in port (Firmware interface) */ |
| |
| MMFirmwareUpdateSettings * |
| mm_iface_modem_firmware_load_update_settings_in_port_finish (MMIfaceModemFirmware *self, |
| GAsyncResult *res, |
| GError **error) |
| { |
| return g_task_propagate_pointer (G_TASK (res), error); |
| } |
| |
| static gboolean |
| modem_is_sahara_supported (MMKernelDevice *kernel_device) |
| { |
| return mm_kernel_device_get_global_property_as_boolean (kernel_device, "ID_MM_QUALCOMM_SAHARA"); |
| } |
| |
| static gboolean |
| modem_is_firehose_supported (MMKernelDevice *kernel_device) |
| { |
| return mm_kernel_device_get_global_property_as_boolean (kernel_device, "ID_MM_QUALCOMM_FIREHOSE"); |
| } |
| |
| void |
| mm_iface_modem_firmware_load_update_settings_in_port (MMIfaceModemFirmware *self, |
| MMPort *port, |
| GAsyncReadyCallback callback, |
| gpointer user_data) |
| { |
| GTask *task; |
| MMModemFirmwareUpdateMethod update_methods; |
| g_autoptr(MMFirmwareUpdateSettings) update_settings = NULL; |
| |
| task = g_task_new (self, NULL, callback, user_data); |
| |
| update_methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE; |
| if (MM_IS_PORT (port)) { |
| MMKernelDevice *kernel_device; |
| |
| kernel_device = mm_port_peek_kernel_device (MM_PORT (port)); |
| |
| if (modem_is_firehose_supported (kernel_device)) |
| update_methods |= MM_MODEM_FIRMWARE_UPDATE_METHOD_FIREHOSE; |
| if (modem_is_sahara_supported (kernel_device)) |
| update_methods |= MM_MODEM_FIRMWARE_UPDATE_METHOD_SAHARA; |
| } |
| |
| update_settings = mm_firmware_update_settings_new (update_methods); |
| g_task_return_pointer (task, g_object_ref (update_settings), (GDestroyNotify)g_object_unref); |
| g_object_unref (task); |
| } |
| |
| /*****************************************************************************/ |
| /* Handle the 'List' method from DBus */ |
| |
| typedef struct { |
| MMIfaceModemFirmware *self; |
| MmGdbusModemFirmware *skeleton; |
| GDBusMethodInvocation *invocation; |
| GList *list; |
| MMFirmwareProperties *current; |
| } HandleListContext; |
| |
| static void |
| handle_list_context_free (HandleListContext *ctx) |
| { |
| if (ctx->list) |
| g_list_free_full (ctx->list, g_object_unref); |
| if (ctx->current) |
| g_object_unref (ctx->current); |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_slice_free (HandleListContext, ctx); |
| } |
| |
| static void |
| load_current_ready (MMIfaceModemFirmware *self, |
| GAsyncResult *res, |
| HandleListContext *ctx) |
| { |
| GVariantBuilder builder; |
| GList *l; |
| GError *error = NULL; |
| |
| ctx->current = MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_current_finish (self, res, &error); |
| if (!ctx->current) { |
| /* Not found isn't fatal */ |
| if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_list_context_free (ctx); |
| return; |
| } |
| mm_obj_dbg (self, "couldn't load current firmware image: %s", error->message); |
| g_clear_error (&error); |
| } |
| |
| /* Build array of dicts */ |
| g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); |
| for (l = ctx->list; l; l = g_list_next (l)) { |
| GVariant *dict; |
| |
| dict = mm_firmware_properties_get_dictionary (MM_FIRMWARE_PROPERTIES (l->data)); |
| g_variant_builder_add_value (&builder, dict); |
| g_variant_unref (dict); |
| } |
| |
| mm_gdbus_modem_firmware_complete_list ( |
| ctx->skeleton, |
| ctx->invocation, |
| (ctx->current ? mm_firmware_properties_get_unique_id (ctx->current) : ""), |
| g_variant_builder_end (&builder)); |
| handle_list_context_free (ctx); |
| } |
| |
| static void |
| load_list_ready (MMIfaceModemFirmware *self, |
| GAsyncResult *res, |
| HandleListContext *ctx) |
| { |
| GError *error = NULL; |
| |
| ctx->list = MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_list_finish (self, res, &error); |
| if (!ctx->list) { |
| /* Not found isn't fatal */ |
| if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_list_context_free (ctx); |
| return; |
| } |
| mm_obj_dbg (self, "couldn't load firmware image list: %s", error->message); |
| g_clear_error (&error); |
| } |
| |
| MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_current ( |
| MM_IFACE_MODEM_FIRMWARE (self), |
| (GAsyncReadyCallback)load_current_ready, |
| ctx); |
| } |
| |
| static void |
| list_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleListContext *ctx) |
| { |
| MMIfaceModemFirmware *self = MM_IFACE_MODEM_FIRMWARE (_self); |
| GError *error = NULL; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_list_context_free (ctx); |
| return; |
| } |
| |
| if (!MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_list || |
| !MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_list_finish || |
| !MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_current || |
| !MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_current_finish) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot list firmware: operation not supported"); |
| handle_list_context_free (ctx); |
| return; |
| } |
| |
| mm_obj_info (self, "processing user request to load firmware list..."); |
| MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_list ( |
| MM_IFACE_MODEM_FIRMWARE (self), |
| (GAsyncReadyCallback)load_list_ready, |
| ctx); |
| } |
| |
| static gboolean |
| handle_list (MmGdbusModemFirmware *skeleton, |
| GDBusMethodInvocation *invocation, |
| MMIfaceModemFirmware *self) |
| { |
| HandleListContext *ctx; |
| |
| ctx = g_slice_new0 (HandleListContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_FIRMWARE, |
| (GAsyncReadyCallback)list_auth_ready, |
| ctx); |
| |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| /* Handle the 'Select' method from DBus */ |
| |
| typedef struct { |
| MMIfaceModemFirmware *self; |
| MmGdbusModemFirmware *skeleton; |
| GDBusMethodInvocation *invocation; |
| gchar *name; |
| } HandleSelectContext; |
| |
| static void |
| handle_select_context_free (HandleSelectContext *ctx) |
| { |
| g_free (ctx->name); |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_slice_free (HandleSelectContext, ctx); |
| } |
| |
| static void |
| change_current_ready (MMIfaceModemFirmware *self, |
| GAsyncResult *res, |
| HandleSelectContext *ctx) |
| { |
| GError *error = NULL; |
| |
| if (!MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->change_current_finish (self, res, &error)) |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| else |
| mm_gdbus_modem_firmware_complete_select (ctx->skeleton, ctx->invocation); |
| handle_select_context_free (ctx); |
| } |
| |
| static void |
| select_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleSelectContext *ctx) |
| { |
| MMIfaceModemFirmware *self = MM_IFACE_MODEM_FIRMWARE (_self); |
| GError *error = NULL; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_select_context_free (ctx); |
| return; |
| } |
| |
| |
| if (!MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->change_current || |
| !MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->change_current_finish) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot select firmware: operation not supported"); |
| handle_select_context_free (ctx); |
| return; |
| } |
| |
| mm_obj_info (self, "processing user request to select firmware..."); |
| MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->change_current ( |
| MM_IFACE_MODEM_FIRMWARE (self), |
| ctx->name, |
| (GAsyncReadyCallback)change_current_ready, |
| ctx); |
| } |
| |
| static gboolean |
| handle_select (MmGdbusModemFirmware *skeleton, |
| GDBusMethodInvocation *invocation, |
| const gchar *name, |
| MMIfaceModemFirmware *self) |
| { |
| HandleSelectContext *ctx; |
| |
| ctx = g_slice_new (HandleSelectContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| ctx->name = g_strdup (name); |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_FIRMWARE, |
| (GAsyncReadyCallback)select_auth_ready, |
| ctx); |
| |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct _InitializationContext InitializationContext; |
| static void interface_initialization_step (GTask *task); |
| |
| typedef enum { |
| INITIALIZATION_STEP_FIRST, |
| INITIALIZATION_STEP_UPDATE_SETTINGS, |
| INITIALIZATION_STEP_LAST |
| } InitializationStep; |
| |
| struct _InitializationContext { |
| MmGdbusModemFirmware *skeleton; |
| InitializationStep step; |
| }; |
| |
| static void |
| initialization_context_free (InitializationContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_free (ctx); |
| } |
| |
| gboolean |
| mm_iface_modem_firmware_initialize_finish (MMIfaceModemFirmware *self, |
| GAsyncResult *res, |
| GError **error) |
| { |
| return g_task_propagate_boolean (G_TASK (res), error); |
| } |
| |
| static gboolean |
| add_generic_version (MMBaseModem *self, |
| MMFirmwareUpdateSettings *update_settings, |
| GError **error) |
| { |
| const gchar *firmware_revision; |
| const gchar *carrier_revision = NULL; |
| g_autofree gchar *combined = NULL; |
| gboolean ignore_carrier = FALSE; |
| |
| firmware_revision = mm_iface_modem_get_revision (MM_IFACE_MODEM (self)); |
| if (!firmware_revision) { |
| g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unknown revision"); |
| return FALSE; |
| } |
| |
| g_object_get (self, |
| MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, &ignore_carrier, |
| NULL); |
| |
| if (!ignore_carrier) |
| mm_iface_modem_get_carrier_config (MM_IFACE_MODEM (self), NULL, &carrier_revision); |
| |
| if (!carrier_revision) { |
| mm_firmware_update_settings_set_version (update_settings, firmware_revision); |
| return TRUE; |
| } |
| |
| combined = g_strdup_printf ("%s - %s", firmware_revision, carrier_revision); |
| mm_firmware_update_settings_set_version (update_settings, combined); |
| return TRUE; |
| } |
| |
| GPtrArray * |
| mm_iface_firmware_build_generic_device_ids (MMIfaceModemFirmware *self, |
| GError **error) |
| { |
| static const gchar *supported_subsystems[] = { "USB", "PCI" }; |
| guint16 vid; |
| guint16 pid; |
| guint16 subsystem_vid; |
| guint16 subsystem_pid; |
| guint16 rid; |
| MMPort *primary = NULL; |
| const gchar *subsystem; |
| const gchar *carrier_config = NULL; |
| g_autoptr(GPtrArray) ids = NULL; |
| guint i; |
| gboolean ignore_carrier = FALSE; |
| |
| vid = mm_base_modem_get_vendor_id (MM_BASE_MODEM (self)); |
| pid = mm_base_modem_get_product_id (MM_BASE_MODEM (self)); |
| subsystem_vid = mm_base_modem_get_subsystem_vendor_id (MM_BASE_MODEM (self)); |
| subsystem_pid = mm_base_modem_get_subsystem_device_id (MM_BASE_MODEM (self)); |
| |
| #if defined WITH_QMI |
| if (MM_IS_BROADBAND_MODEM_QMI (self)) |
| primary = MM_PORT (mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (self))); |
| #endif |
| #if defined WITH_MBIM |
| if (!primary && MM_IS_BROADBAND_MODEM_MBIM (self)) |
| primary = MM_PORT (mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self))); |
| #endif |
| if (!primary) |
| primary = MM_PORT (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self))); |
| |
| if (!primary) { |
| g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, |
| "No valid primary port"); |
| return NULL; |
| } |
| |
| rid = mm_kernel_device_get_physdev_revision (mm_port_peek_kernel_device (primary)); |
| |
| subsystem = mm_kernel_device_get_physdev_subsystem (mm_port_peek_kernel_device (primary)); |
| if (!subsystem) { |
| g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, |
| "Unknown device subsystem"); |
| return NULL; |
| } |
| |
| for (i = 0; i < G_N_ELEMENTS (supported_subsystems); i++) { |
| if (g_ascii_strcasecmp (supported_subsystems[i], subsystem) == 0) |
| break; |
| } |
| if (i == G_N_ELEMENTS (supported_subsystems)) { |
| g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, |
| "Unsupported subsystem: %s", subsystem); |
| return NULL; |
| } |
| |
| g_object_get (self, |
| MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, &ignore_carrier, |
| NULL); |
| |
| if (!ignore_carrier) |
| mm_iface_modem_get_carrier_config (MM_IFACE_MODEM (self), &carrier_config, NULL); |
| |
| ids = g_ptr_array_new_with_free_func (g_free); |
| if (carrier_config) { |
| g_autofree gchar *carrier = NULL; |
| |
| carrier = g_ascii_strup (carrier_config, -1); |
| |
| /* Expect non-zero values for PCI devices only */ |
| if (subsystem_vid && subsystem_pid) |
| g_ptr_array_add (ids, g_strdup_printf ("%s\\SSVID_%04X&SSPID_%04X&REV_%04X&CARRIER_%s", |
| supported_subsystems[i], subsystem_vid, |
| subsystem_pid, rid, carrier)); |
| |
| g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X&PID_%04X&REV_%04X&CARRIER_%s", |
| supported_subsystems[i], vid, pid, rid, carrier)); |
| } |
| g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X&PID_%04X&REV_%04X", |
| supported_subsystems[i], vid, pid, rid)); |
| g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X&PID_%04X", |
| supported_subsystems[i], vid, pid)); |
| g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X", |
| supported_subsystems[i], vid)); |
| g_ptr_array_add (ids, NULL); |
| |
| return g_steal_pointer (&ids); |
| } |
| |
| static void |
| load_update_settings_ready (MMIfaceModemFirmware *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| InitializationContext *ctx; |
| MMFirmwareUpdateSettings *update_settings; |
| GError *error = NULL; |
| GVariant *variant = NULL; |
| g_autoptr(GPtrArray) ids = NULL; |
| |
| ctx = g_task_get_task_data (task); |
| |
| update_settings = MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_update_settings_finish (self, res, &error); |
| if (!update_settings) { |
| mm_obj_dbg (self, "couldn't load update settings: %s", error->message); |
| g_error_free (error); |
| goto out; |
| } |
| |
| /* If the plugin didn't specify custom device ids, add the default ones ourselves */ |
| if (!mm_firmware_update_settings_get_device_ids (update_settings)) { |
| mm_obj_dbg (self, "No device ids set by plugin, adding generic ids"); |
| ids = mm_iface_firmware_build_generic_device_ids (self, &error); |
| if (error) { |
| mm_obj_warn (self, "couldn't build device ids: %s", error->message); |
| g_error_free (error); |
| g_clear_object (&update_settings); |
| goto out; |
| } |
| |
| mm_firmware_update_settings_set_device_ids (update_settings, (const gchar **)ids->pdata); |
| } |
| |
| /* If the plugin didn't specify custom version, add the default one ourselves */ |
| if (!mm_firmware_update_settings_get_version (update_settings) && |
| !add_generic_version (MM_BASE_MODEM (self), update_settings, &error)) { |
| mm_obj_warn (self, "couldn't set version: %s", error->message); |
| g_error_free (error); |
| g_clear_object (&update_settings); |
| goto out; |
| } |
| |
| out: |
| if (update_settings) { |
| variant = mm_firmware_update_settings_get_variant (update_settings); |
| g_object_unref (update_settings); |
| } |
| mm_gdbus_modem_firmware_set_update_settings (ctx->skeleton, variant); |
| if (variant) |
| g_variant_unref (variant); |
| |
| /* Go on to next step */ |
| ctx->step++; |
| interface_initialization_step (task); |
| } |
| |
| static void |
| interface_initialization_step (GTask *task) |
| { |
| MMIfaceModemFirmware *self; |
| InitializationContext *ctx; |
| |
| /* Don't run new steps if we're cancelled */ |
| if (g_task_return_error_if_cancelled (task)) { |
| g_object_unref (task); |
| return; |
| } |
| |
| self = g_task_get_source_object (task); |
| ctx = g_task_get_task_data (task); |
| |
| switch (ctx->step) { |
| case INITIALIZATION_STEP_FIRST: |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_UPDATE_SETTINGS: |
| if (MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_update_settings && |
| MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_update_settings_finish) { |
| MM_IFACE_MODEM_FIRMWARE_GET_IFACE (self)->load_update_settings ( |
| self, |
| (GAsyncReadyCallback)load_update_settings_ready, |
| task); |
| return; |
| } |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_LAST: |
| /* We are done without errors! */ |
| |
| /* Handle method invocations */ |
| g_object_connect (ctx->skeleton, |
| "signal::handle-list", G_CALLBACK (handle_list), self, |
| "signal::handle-select", G_CALLBACK (handle_select), self, |
| NULL); |
| |
| /* Finally, export the new interface */ |
| mm_gdbus_object_skeleton_set_modem_firmware (MM_GDBUS_OBJECT_SKELETON (self), |
| MM_GDBUS_MODEM_FIRMWARE (ctx->skeleton)); |
| |
| g_task_return_boolean (task, TRUE); |
| g_object_unref (task); |
| return; |
| |
| default: |
| break; |
| } |
| |
| g_assert_not_reached (); |
| } |
| |
| void |
| mm_iface_modem_firmware_initialize (MMIfaceModemFirmware *self, |
| GCancellable *cancellable, |
| GAsyncReadyCallback callback, |
| gpointer user_data) |
| { |
| InitializationContext *ctx; |
| MmGdbusModemFirmware *skeleton = NULL; |
| GTask *task; |
| |
| /* Did we already create it? */ |
| g_object_get (self, |
| MM_IFACE_MODEM_FIRMWARE_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) { |
| skeleton = mm_gdbus_modem_firmware_skeleton_new (); |
| g_object_set (self, |
| MM_IFACE_MODEM_FIRMWARE_DBUS_SKELETON, skeleton, |
| NULL); |
| } |
| |
| /* Perform async initialization here */ |
| ctx = g_new0 (InitializationContext, 1); |
| ctx->step = INITIALIZATION_STEP_FIRST; |
| ctx->skeleton = skeleton; |
| |
| task = g_task_new (self, cancellable, callback, user_data); |
| g_task_set_task_data (task, ctx, (GDestroyNotify)initialization_context_free); |
| |
| interface_initialization_step (task); |
| } |
| |
| void |
| mm_iface_modem_firmware_shutdown (MMIfaceModemFirmware *self) |
| { |
| g_return_if_fail (MM_IS_IFACE_MODEM_FIRMWARE (self)); |
| |
| /* Unexport DBus interface and remove the skeleton */ |
| mm_gdbus_object_skeleton_set_modem_firmware (MM_GDBUS_OBJECT_SKELETON (self), NULL); |
| g_object_set (self, |
| MM_IFACE_MODEM_FIRMWARE_DBUS_SKELETON, NULL, |
| NULL); |
| } |
| |
| /*****************************************************************************/ |
| |
| static void |
| mm_iface_modem_firmware_default_init (MMIfaceModemFirmwareInterface *iface) |
| { |
| static gsize initialized = 0; |
| |
| if (!g_once_init_enter (&initialized)) |
| return; |
| |
| /* Properties */ |
| g_object_interface_install_property ( |
| iface, |
| g_param_spec_object (MM_IFACE_MODEM_FIRMWARE_DBUS_SKELETON, |
| "Firmware DBus skeleton", |
| "DBus skeleton for the Firmware interface", |
| MM_GDBUS_TYPE_MODEM_FIRMWARE_SKELETON, |
| G_PARAM_READWRITE)); |
| |
| g_object_interface_install_property ( |
| iface, |
| g_param_spec_boolean (MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, |
| "Ignore carrier info in firmware details", |
| "Whether carrier info (version, name) should be ignored when showing the firmware details", |
| FALSE, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); |
| |
| g_once_init_leave (&initialized, 1); |
| } |