static gboolean handle_set_profile (MmGdbusTest *skeleton, GDBusMethodInvocation *invocation, const gchar *id, const gchar *plugin_name, const gchar *const *ports, MMBaseManager *self) { MMPlugin *plugin; MMDevice *device; gchar *physdev; GError *error = NULL; mm_info ("Test profile set to: '%s'", id); /* Create device and keep it listed in the Manager */ physdev = g_strdup_printf ("/virtual/%s", id); device = mm_device_virtual_new (physdev, TRUE); g_hash_table_insert (self->priv->devices, physdev, device); /* Grab virtual ports */ mm_device_virtual_grab_ports (device, (const gchar **)ports); /* Set plugin to use */ plugin = mm_plugin_manager_peek_plugin (self->priv->plugin_manager, plugin_name); if (!plugin) { error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, "Requested plugin '%s' not found", plugin_name); mm_warn ("Couldn't set plugin for virtual device at '%s': %s", mm_device_get_path (device), error->message); goto out; } mm_device_set_plugin (device, G_OBJECT (plugin)); /* Create modem */ if (!mm_device_create_modem (device, self->priv->object_manager, &error)) { mm_warn ("Couldn't create modem for virtual device at '%s': %s", mm_device_get_path (device), error->message); goto out; } mm_info ("Modem for virtual device at '%s' successfully created", mm_device_get_path (device)); out: if (error) { mm_device_remove_modem (device); g_hash_table_remove (self->priv->devices, mm_device_get_path (device)); g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } else mm_gdbus_test_complete_set_profile (skeleton, invocation); return TRUE; }
static MMPlugin * load_plugin (const gchar *path) { MMPlugin *plugin = NULL; GModule *module; MMPluginCreateFunc plugin_create_func; gint *major_plugin_version; gint *minor_plugin_version; gchar *path_display; /* Get printable UTF-8 string of the path */ path_display = g_filename_display_name (path); module = g_module_open (path, G_MODULE_BIND_LAZY); if (!module) { g_warning ("Could not load plugin '%s': %s", path_display, g_module_error ()); goto out; } if (!g_module_symbol (module, "mm_plugin_major_version", (gpointer *) &major_plugin_version)) { g_warning ("Could not load plugin '%s': Missing major version info", path_display); goto out; } if (*major_plugin_version != MM_PLUGIN_MAJOR_VERSION) { g_warning ("Could not load plugin '%s': Plugin major version %d, %d is required", path_display, *major_plugin_version, MM_PLUGIN_MAJOR_VERSION); goto out; } if (!g_module_symbol (module, "mm_plugin_minor_version", (gpointer *) &minor_plugin_version)) { g_warning ("Could not load plugin '%s': Missing minor version info", path_display); goto out; } if (*minor_plugin_version != MM_PLUGIN_MINOR_VERSION) { g_warning ("Could not load plugin '%s': Plugin minor version %d, %d is required", path_display, *minor_plugin_version, MM_PLUGIN_MINOR_VERSION); goto out; } if (!g_module_symbol (module, "mm_plugin_create", (gpointer *) &plugin_create_func)) { g_warning ("Could not load plugin '%s': %s", path_display, g_module_error ()); goto out; } plugin = (*plugin_create_func) (); if (plugin) { g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module); } else mm_warn ("Could not load plugin '%s': initialization failed", path_display); out: if (module && !plugin) g_module_close (module); g_free (path_display); return plugin; }
void mm_port_qmi_close (MMPortQmi *self) { GList *l; GError *error = NULL; g_return_if_fail (MM_IS_PORT_QMI (self)); if (!self->priv->qmi_device) return; /* Release all allocated clients */ for (l = self->priv->services; l; l = g_list_next (l)) { ServiceInfo *info = l->data; mm_dbg ("Releasing client for service '%s'...", qmi_service_get_string (info->service)); qmi_device_release_client (self->priv->qmi_device, info->client, QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID, 3, NULL, NULL, NULL); g_clear_object (&info->client); } g_list_free_full (self->priv->services, (GDestroyNotify)g_free); self->priv->services = NULL; /* Close and release the device */ if (!qmi_device_close (self->priv->qmi_device, &error)) { mm_warn ("Couldn't properly close QMI device: %s", error->message); g_error_free (error); } g_clear_object (&self->priv->qmi_device); }
static void initialize_ready (MMBaseModem *self, GAsyncResult *res) { GError *error = NULL; if (mm_base_modem_initialize_finish (self, res, &error)) { mm_dbg ("modem properly initialized"); mm_base_modem_set_valid (self, TRUE); return; } /* Wrong state is returned when modem is found locked */ if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE)) { /* Even with initialization errors, we do set the state to valid, so * that the modem gets exported and the failure notified to the user. */ mm_dbg ("Couldn't finish initialization in the current state: '%s'", error->message); g_error_free (error); mm_base_modem_set_valid (self, TRUE); return; } /* Really fatal, we cannot even export the failed modem (e.g. error before * even trying to enable the Modem interface */ mm_warn ("couldn't initialize the modem: '%s'", error->message); g_error_free (error); }
static void emrdy_ready (MMBaseModem *self, GAsyncResult *res, EnablingModemInitContext *ctx) { GError *error = NULL; /* EMRDY unsolicited response might have happened between the command * submission and the response. This was seen once: * * (ttyACM0): --> 'AT*EMRDY?<CR>' * (ttyACM0): <-- 'T*EMRD<CR><LF>*EMRDY: 1<CR><LF>Y?' * * So suppress the warning if the unsolicited handler handled the response * before we get here. */ if (!mm_base_modem_at_command_finish (self, res, &error)) { if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) mm_warn ("timed out waiting for EMRDY response."); else ctx->self->priv->have_emrdy = TRUE; g_error_free (error); } run_enabling_init_sequence (ctx); }
static void device_support_check_ready (MMPluginManager *plugin_manager, GAsyncResult *res, FindDeviceSupportContext *ctx) { GError *error = NULL; MMPlugin *plugin; /* Receive plugin result from the plugin manager */ plugin = mm_plugin_manager_device_support_check_finish (plugin_manager, res, &error); if (!plugin) { mm_info ("Couldn't check support for device at '%s': %s", mm_device_get_path (ctx->device), error->message); g_error_free (error); find_device_support_context_free (ctx); return; } /* Set the plugin as the one expected in the device */ mm_device_set_plugin (ctx->device, G_OBJECT (plugin)); g_object_unref (plugin); if (!mm_device_create_modem (ctx->device, ctx->self->priv->object_manager, &error)) { mm_warn ("Couldn't create modem for device at '%s': %s", mm_device_get_path (ctx->device), error->message); g_error_free (error); find_device_support_context_free (ctx); return; } /* Modem now created */ mm_info ("Modem for device at '%s' successfully created", mm_device_get_path (ctx->device)); find_device_support_context_free (ctx); }
static void connect_3gpp_qmiconnect_ready (MMBaseModem *modem, GAsyncResult *res, DetailedConnectContext *ctx) { const gchar *result; GError *error = NULL; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem), res, &error); if (!result) { mm_warn ("QMI connection failed: %s", error->message); g_simple_async_result_take_error (ctx->result, error); detailed_connect_context_complete_and_free (ctx); return; } /* * The connection takes a bit of time to set up, but there's no * asynchronous notification from the modem when this has * happened. Instead, we need to poll the modem to see if it's * ready. */ g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx); }
static void name_lost_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { /* Note that we're not allowing replacement, so once the name acquired, the * process won't lose it. */ if (!name) mm_warn ("Could not get the system bus. Make sure " "the message bus daemon is running!"); else mm_warn ("Could not acquire the '%s' service name", name); if (manager) g_object_set (manager, MM_BASE_MANAGER_CONNECTION, NULL, NULL); g_main_loop_quit (loop); }
static void connection_enabled (MMAtSerialPort *port, GMatchInfo *match_info, gpointer user_data) { MMModemIcera *self = MM_MODEM_ICERA (user_data); MMAtSerialPort *primary; char *str; int status, cid, tmp; cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); if (cid < 0) return; str = g_match_info_fetch (match_info, 1); g_return_if_fail (str != NULL); tmp = atoi (str); g_free (str); /* Make sure the unsolicited message's CID matches the current CID */ if (tmp != cid) return; str = g_match_info_fetch (match_info, 2); g_return_if_fail (str != NULL); status = atoi (str); g_free (str); switch (status) { case 0: /* Disconnected */ if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_CONNECTED) mm_modem_disconnect (MM_MODEM (self), icera_disconnect_done, NULL); break; case 1: /* Connected */ connect_pending_done (self); break; case 2: /* Connecting */ break; case 3: /* Call setup failure? */ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM(self), MM_AT_PORT_FLAG_PRIMARY); g_assert (primary); /* Get additional error details */ mm_at_serial_port_queue_command (primary, "AT%IER?", 3, query_network_error_code_done, self); break; default: mm_warn ("Unknown Icera connect status %d", status); break; } }
static void find_device_support_ready (MMPluginManager *plugin_manager, GAsyncResult *result, FindDeviceSupportContext *ctx) { GError *error = NULL; if (!mm_plugin_manager_find_device_support_finish (plugin_manager, result, &error)) { mm_warn ("Couldn't find support for device at '%s': %s", mm_device_get_path (ctx->device), error->message); g_error_free (error); } else if (!mm_device_create_modem (ctx->device, ctx->self->priv->object_manager, &error)) { mm_warn ("Couldn't create modem for device at '%s': %s", mm_device_get_path (ctx->device), error->message); g_error_free (error); } else { mm_info ("Modem for device at '%s' successfully created", mm_device_get_path (ctx->device)); } find_device_support_context_free (ctx); }
static void get_local_timestamp_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMModemIceraTimestamp *timestamp; char sign; int offset; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; if (error) { info->error = g_error_copy (error); goto out; } timestamp = g_malloc0 (sizeof (MMModemIceraTimestamp)); if (g_str_has_prefix (response->str, "*TLTS: ") && sscanf (response->str + 7, "\"%02d/%02d/%02d,%02d:%02d:%02d%c%02d\"", ×tamp->year, ×tamp->month, ×tamp->day, ×tamp->hour, ×tamp->minute, ×tamp->second, &sign, &offset) == 8) { if (sign == '-') timestamp->tz_offset = -offset; else timestamp->tz_offset = offset; mm_callback_info_set_result (info, timestamp, g_free); } else { mm_warn ("Unknown *TLTS response: %s", response->str); mm_callback_info_set_result (info, NULL, g_free); g_free (timestamp); } out: mm_callback_info_schedule (info); }
static void grab_port (MMManager *manager, MMPlugin *plugin, GUdevDevice *device, GUdevDevice *physical_device) { GError *error = NULL; MMBaseModem *modem; MMBaseModem *existing; existing = g_hash_table_lookup (manager->priv->modems, g_udev_device_get_sysfs_path (physical_device)); /* While grabbing the first port, modem will get created */ modem = mm_plugin_grab_port (plugin, g_udev_device_get_subsystem (device), g_udev_device_get_name (device), existing, &error); if (!modem) { mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s", mm_plugin_get_name (plugin), g_udev_device_get_subsystem (device), g_udev_device_get_name (device), error ? error->code : -1, (error && error->message) ? error->message : "(unknown)"); g_clear_error (&error); if (existing) check_export_modem (manager, existing); return; } mm_info ("(%s): modem %s claimed port %s", mm_plugin_get_name (plugin), mm_base_modem_get_device (modem), g_udev_device_get_name (device)); if (existing) { g_assert (existing == modem); check_export_modem (manager, modem); } else { /* If the modem was just created, store it */ add_modem (manager, modem, plugin); } }
static void mm_auth_provider_polkit_init (MMAuthProviderPolkit *self) { GError *error = NULL; self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), MM_TYPE_AUTH_PROVIDER_POLKIT, MMAuthProviderPolkitPrivate); self->priv->authority = polkit_authority_get_sync (NULL, &error); if (!self->priv->authority) { /* NOTE: we failed to create the polkit authority, but we still create * our AuthProvider. Every request will fail, though. */ mm_warn ("failed to create PolicyKit authority: '%s'", error ? error->message : "unknown"); g_clear_error (&error); } }
static void modem_power_up (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { mm_warn ("Not in full functionality status, power-up command is needed. " "Note that it may reboot the modem."); /* Try to go to full functionality mode without rebooting the system. * Works well if we previously switched off the power with CFUN=4 */ mm_base_modem_at_command (MM_BASE_MODEM (self), "+CFUN=1,0", 3, FALSE, callback, user_data); }
static void serial_port_timed_out_cb (MMSerialPort *port, guint n_consecutive_timeouts, gpointer user_data) { MMBaseModem *self = (MM_BASE_MODEM (user_data)); if (self->priv->max_timeouts > 0 && n_consecutive_timeouts >= self->priv->max_timeouts) { mm_warn ("(%s/%s) port timed out %u times, marking modem '%s' as disabled", mm_port_type_get_string (mm_port_get_port_type (MM_PORT (port))), mm_port_get_device (MM_PORT (port)), n_consecutive_timeouts, g_dbus_object_get_object_path (G_DBUS_OBJECT (self))); /* Only set action to invalidate modem if not already done */ g_cancellable_cancel (self->priv->cancellable); } }
static void serial_probe_qcdm_parse_response (MMQcdmSerialPort *port, GByteArray *response, GError *error, MMPortProbe *self) { QcdmResult *result; gint err = QCDM_SUCCESS; gboolean is_qcdm = FALSE; /* Just the initial poke; ignore it */ if (!self) return; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; if (!error) { /* Parse the response */ result = qcdm_cmd_version_info_result ((const gchar *) response->data, response->len, &err); if (!result) { mm_warn ("(%s) failed to parse QCDM version info command result: %d", self->priv->name, err); } else { /* yay, probably a QCDM port */ is_qcdm = TRUE; qcdm_result_unref (result); } } /* Set probing result */ mm_port_probe_set_result_qcdm (self, is_qcdm); /* Reschedule probing */ serial_probe_schedule (self); }
static void connect_3gpp_qmistatus_ready (MMBaseModem *modem, GAsyncResult *res, DetailedConnectContext *ctx) { const gchar *result; GError *error = NULL; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (ctx->modem), res, &error); if (!result) { mm_warn ("QMI connection status failed: %s", error->message); g_simple_async_result_take_error (ctx->result, error); detailed_connect_context_complete_and_free (ctx); return; } result = mm_strip_tag (result, "$NWQMISTATUS:"); if (g_strrstr(result, "QMI State: CONNECTED")) { mm_dbg("Connected"); detailed_connect_context_complete_and_free_successful (ctx); return; } else { mm_dbg("Error: '%s'", result); if (ctx->retries > 0) { ctx->retries--; mm_dbg("Retrying status check in a second. %d retries left.", ctx->retries); g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx); return; } g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "%s", result); } detailed_connect_context_complete_and_free (ctx); }
static void bus_acquired_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { GError *error = NULL; mm_dbg ("Bus acquired, creating manager..."); /* Create Manager object */ g_assert (!manager); manager = mm_base_manager_new (connection, mm_context_get_test_plugin_dir (), !mm_context_get_test_no_auto_scan (), mm_context_get_test_enable (), &error); if (!manager) { mm_warn ("Could not create manager: %s", error->message); g_error_free (error); g_main_loop_quit (loop); return; } }
static void supports_port_ready_cb (MMPlugin *plugin, GAsyncResult *result, SupportsInfo *info) { MMPluginSupportsResult support_result; GError *error = NULL; /* Get supports check results */ support_result = mm_plugin_supports_port_finish (plugin, result, &error); if (error) { mm_warn ("(%s): (%s) error when checking support: '%s'", mm_plugin_get_name (plugin), info->name, error->message); g_error_free (error); } switch (support_result) { case MM_PLUGIN_SUPPORTS_PORT_SUPPORTED: /* Found a best plugin */ info->best_plugin = plugin; if (info->suggested_plugin && info->suggested_plugin != plugin) { /* The last plugin we tried said it supported this port, but it * doesn't correspond with the one we're being suggested. */ g_warn_if_reached (); } mm_dbg ("(%s): (%s) found best plugin for port", mm_plugin_get_name (info->best_plugin), info->name); info->current = NULL; /* Schedule checking support, which will end the operation */ info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, info); break; case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED: if (info->suggested_plugin) { if (info->suggested_plugin == plugin) { /* If the plugin that just completed the support check claims * not to support this port, but this plugin is clearly the * right plugin since it claimed this port's physical modem, * just drop the port. */ mm_dbg ("(%s/%s): ignoring port unsupported by physical modem's plugin", info->subsys, info->name); info->best_plugin = NULL; info->current = NULL; } else { /* The last plugin we tried is NOT the one we got suggested, so * directly check support with the suggested plugin. If we * already checked its support, it won't be checked again. */ info->current = g_slist_find (info->current, info->suggested_plugin); } } else { /* If the plugin knows it doesn't support the modem, just keep on * checking the next plugin. */ info->current = g_slist_next (info->current); } info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, info); break; case MM_PLUGIN_SUPPORTS_PORT_DEFER: /* Try with the suggested one after being deferred */ if (info->suggested_plugin) { mm_dbg ("(%s): (%s) deferring support check, suggested: %s", mm_plugin_get_name (MM_PLUGIN (info->current->data)), info->name, mm_plugin_get_name (MM_PLUGIN (info->suggested_plugin))); info->current = g_slist_find (info->current, info->suggested_plugin); } else { mm_dbg ("(%s): (%s) deferring support check", mm_plugin_get_name (MM_PLUGIN (info->current->data)), info->name); } /* Schedule checking support */ info->source_id = g_timeout_add_seconds (SUPPORTS_DEFER_TIMEOUT_SECS, (GSourceFunc)find_port_support_idle, info); break; case MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED: /* If we arrived here and we already have a plugin suggested, use it */ if (info->suggested_plugin) { mm_dbg ("(%s): (%s) task completed, got suggested plugin", mm_plugin_get_name (info->suggested_plugin), info->name); /* Schedule checking support, which will end the operation */ info->best_plugin = info->suggested_plugin; info->current = NULL; info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, info); } else { /* We are deferred until a suggested plugin is given. If last supports task * of a given device is finished without finding a best plugin, this task * will get finished reporting unsupported. */ mm_dbg ("(%s) deferring support check until result suggested", info->name); info->defer_until_suggested = TRUE; } break; } }
int main (int argc, char *argv[]) { GMainLoop *inner; GError *err = NULL; guint name_id; g_type_init (); /* Setup application context */ mm_context_init (argc, argv); if (!mm_log_setup (mm_context_get_log_level (), mm_context_get_log_file (), mm_context_get_timestamps (), mm_context_get_relative_timestamps (), mm_context_get_debug (), &err)) { g_warning ("Failed to set up logging: %s", err->message); g_error_free (err); exit (1); } g_unix_signal_add (SIGTERM, quit_cb, NULL); g_unix_signal_add (SIGINT, quit_cb, NULL); mm_info ("ModemManager (version " MM_DIST_VERSION ") starting in %s bus...", mm_context_get_test_session () ? "session" : "system"); /* Acquire name, don't allow replacement */ name_id = g_bus_own_name (mm_context_get_test_session () ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM, MM_DBUS_SERVICE, G_BUS_NAME_OWNER_FLAGS_NONE, bus_acquired_cb, name_acquired_cb, name_lost_cb, NULL, NULL); /* Go into the main loop */ loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); /* Clear the global variable, so that subsequent requests to * exit succeed. */ inner = loop; loop = NULL; if (manager) { GTimer *timer; mm_base_manager_shutdown (manager); /* Wait for all modems to be disabled and removed, but don't wait * forever: if disabling the modems takes longer than 20s, just * shutdown anyway. */ timer = g_timer_new (); while (mm_base_manager_num_modems (manager) && g_timer_elapsed (timer, NULL) < (gdouble)MAX_SHUTDOWN_TIME_SECS) { GMainContext *ctx = g_main_loop_get_context (inner); g_main_context_iteration (ctx, FALSE); g_usleep (50); } if (mm_base_manager_num_modems (manager)) mm_warn ("Disabling modems took too long, " "shutting down with '%u' modems around", mm_base_manager_num_modems (manager)); g_object_unref (manager); g_timer_destroy (timer); } g_main_loop_unref (inner); g_bus_unown_name (name_id); mm_info ("ModemManager is shut down"); mm_log_shutdown (); return 0; }
void mm_base_modem_release_port (MMBaseModem *self, const gchar *subsys, const gchar *name) { gchar *key; MMPort *port; GList *l; g_return_if_fail (MM_IS_BASE_MODEM (self)); g_return_if_fail (name != NULL); g_return_if_fail (subsys != NULL); if (!g_str_equal (subsys, "tty") && !g_str_equal (subsys, "net")) return; key = get_hash_key (subsys, name); /* Find the port */ port = g_hash_table_lookup (self->priv->ports, key); if (!port) { mm_warn ("(%s/%s): cannot release port, not found", subsys, name); g_free (key); return; } if (port == (MMPort *)self->priv->primary) { /* Cancel modem-wide cancellable; no further actions can be done * without a primary port. */ g_cancellable_cancel (self->priv->cancellable); g_clear_object (&self->priv->primary); } l = g_list_find (self->priv->data, port); if (l) { g_object_unref (l->data); self->priv->data = g_list_delete_link (self->priv->data, l); } if (port == (MMPort *)self->priv->secondary) g_clear_object (&self->priv->secondary); if (port == (MMPort *)self->priv->qcdm) g_clear_object (&self->priv->qcdm); if (port == (MMPort *)self->priv->gps_control) g_clear_object (&self->priv->gps_control); if (port == (MMPort *)self->priv->gps) g_clear_object (&self->priv->gps); #if defined WITH_QMI l = g_list_find (self->priv->qmi, port); if (l) { g_object_unref (l->data); self->priv->qmi = g_list_delete_link (self->priv->qmi, l); } #endif /* Remove it from the tracking HT */ mm_dbg ("(%s/%s) type %s released from %s", subsys, name, mm_port_type_get_string (mm_port_get_port_type (port)), mm_port_get_device (port)); g_hash_table_remove (self->priv->ports, key); g_free (key); }
MMQmiPort * mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error) { MMQmiPort *found; GUdevClient *client; GUdevDevice *data_device; GUdevDevice *data_device_parent; GList *l; if (mm_port_get_subsys (data) != MM_PORT_SUBSYS_NET) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Cannot look for QMI port associated to a non-net data port"); return NULL; } /* don't listen for uevents */ client = g_udev_client_new (NULL); /* Get udev device for the data port */ data_device = (g_udev_client_query_by_subsystem_and_name ( client, "net", mm_port_get_device (data))); if (!data_device) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't find udev device for port 'net/%s'", mm_port_get_device (data)); g_object_unref (client); return NULL; } /* Get parent of the data device */ data_device_parent = g_udev_device_get_parent (data_device); if (!data_device_parent) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't get udev device parent for port 'net/%s'", mm_port_get_device (data)); g_object_unref (data_device); g_object_unref (client); return NULL; } /* Now walk the list of QMI ports looking for a match */ found = NULL; for (l = self->priv->qmi; l && !found; l = g_list_next (l)) { GUdevDevice *qmi_device; GUdevDevice *qmi_device_parent; /* Get udev device for the QMI port */ qmi_device = (g_udev_client_query_by_subsystem_and_name ( client, "usb", mm_port_get_device (MM_PORT (l->data)))); if (!qmi_device) { qmi_device = (g_udev_client_query_by_subsystem_and_name ( client, "usbmisc", mm_port_get_device (MM_PORT (l->data)))); if (!qmi_device) { mm_warn ("Couldn't get udev device for QMI port '%s'", mm_port_get_device (MM_PORT (l->data))); continue; } } /* Get parent of the QMI device */ qmi_device_parent = g_udev_device_get_parent (qmi_device); g_object_unref (qmi_device); if (!data_device_parent) { mm_warn ("Couldn't get udev device parent for QMI port '%s'", mm_port_get_device (MM_PORT (l->data))); continue; } if (g_str_equal (g_udev_device_get_sysfs_path (data_device_parent), g_udev_device_get_sysfs_path (qmi_device_parent))) found = MM_QMI_PORT (l->data); g_object_unref (qmi_device_parent); } g_object_unref (data_device_parent); g_object_unref (data_device); g_object_unref (client); if (!found) { /* For the case where we have only 1 data port and 1 QMI port and they * don't match with the previous rules (e.g. in some Huawei modems), * just return the found one */ if (g_list_length (self->priv->data) == 1 && g_list_length (self->priv->qmi) == 1 && self->priv->data->data == data) { mm_info ("Assuming QMI port '%s' is associated to net/%s", mm_port_get_device (MM_PORT (self->priv->qmi->data)), mm_port_get_device (data)); found = MM_QMI_PORT (self->priv->qmi->data); } else { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, "Couldn't find associated QMI port for 'net/%s'", mm_port_get_device (data)); return NULL; } } return found; }
static void serial_probe_qcdm_parse_response (MMQcdmSerialPort *port, GByteArray *response, GError *error, MMPortProbe *self) { QcdmResult *result; gint err = QCDM_SUCCESS; gboolean is_qcdm = FALSE; gboolean retry = FALSE; PortProbeRunTask *task = self->priv->task; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; if (!error) { /* Parse the response */ result = qcdm_cmd_version_info_result ((const gchar *) response->data, response->len, &err); if (!result) { mm_warn ("(%s/%s) failed to parse QCDM version info command result: %d", g_udev_device_get_subsystem (self->priv->port), g_udev_device_get_name (self->priv->port), err); retry = TRUE; } else { /* yay, probably a QCDM port */ is_qcdm = TRUE; qcdm_result_unref (result); } } else { if (!g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) mm_dbg ("QCDM probe error: (%d) %s", error->code, error->message); retry = TRUE; } if (retry) { GByteArray *cmd2; cmd2 = g_object_steal_data (G_OBJECT (self), "cmd2"); if (cmd2) { /* second try */ mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), cmd2, 3, NULL, (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, self); return; } /* no more retries left */ } /* Set probing result */ mm_port_probe_set_result_qcdm (self, is_qcdm); /* Reschedule probing */ serial_probe_schedule (self); }
static void sysinfo_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; GRegex *r; GMatchInfo *match_info; const char *reply; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; if (error) { /* Leave superclass' reg state alone if AT^SYSINFO isn't supported */ goto done; } reply = strip_response (response->str, "^SYSINFO:"); /* Format is "<srv_status>,<srv_domain>,<roam_status>,<sys_mode>,<sim_state>" */ r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { mm_warn ("Huawei: ^SYSINFO parse regex creation failed."); goto done; } g_regex_match (r, reply, 0, &match_info); if (g_match_info_get_match_count (match_info) >= 5) { MMModemCdmaRegistrationState reg_state; guint32 val = 0; /* At this point the generic code already knows we've been registered */ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; if (uint_from_match_item (match_info, 1, &val)) { if (val == 2) { /* Service available, check roaming state */ val = 0; if (uint_from_match_item (match_info, 3, &val)) { if (val == 0) reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME; else if (val == 1) reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING; } } } /* Check service type */ val = 0; if (uint_from_match_item (match_info, 4, &val)) { if (val == 2) mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); else if (val == 4) mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state); else if (val == 8) { mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state); } } else { /* Say we're registered to something even though sysmode parsing failed */ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); } } else mm_warn ("Huawei: failed to parse ^SYSINFO response."); g_match_info_free (match_info); g_regex_unref (r); done: mm_callback_info_schedule (info); }
MMBaseModem * mm_plugin_create_modem (MMPlugin *self, MMDevice *device, GError **error) { MMBaseModem *modem = NULL; GList *port_probes, *l; port_probes = mm_device_peek_port_probe_list (device); /* Let the plugin create the modem from the port probe results */ modem = MM_PLUGIN_GET_CLASS (self)->create_modem (MM_PLUGIN (self), mm_device_get_path (device), mm_device_get_drivers (device), mm_device_get_vendor (device), mm_device_get_product (device), port_probes, error); if (modem) { /* Grab each port */ for (l = port_probes; l; l = g_list_next (l)) { GError *inner_error = NULL; MMPortProbe *probe = MM_PORT_PROBE (l->data); gboolean grabbed; /* If grabbing a port fails, just warn. We'll decide if the modem is * valid or not when all ports get organized */ /* We apply again the subsystem filter, as the port may have been * probed and accepted by the generic plugin, which is overwritten * by the specific one when needed. */ if (apply_subsystem_filter (self, mm_port_probe_peek_port (probe))) { grabbed = FALSE; inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "unsupported subsystem: '%s'", mm_port_probe_get_port_subsys (probe)); } #if !defined WITH_QMI else if (mm_port_probe_get_port_type (probe) == MM_PORT_TYPE_NET && g_str_equal (mm_device_utils_get_port_driver (mm_port_probe_peek_port (probe)), "qmi_wwan")) { grabbed = FALSE; inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "ignoring QMI net port"); } #endif else if (MM_PLUGIN_GET_CLASS (self)->grab_port) grabbed = MM_PLUGIN_GET_CLASS (self)->grab_port (MM_PLUGIN (self), modem, probe, &inner_error); else grabbed = mm_base_modem_grab_port (modem, mm_port_probe_get_port_subsys (probe), mm_port_probe_get_port_name (probe), mm_port_probe_get_port_type (probe), MM_AT_PORT_FLAG_NONE, &inner_error); if (!grabbed) { mm_warn ("Could not grab port (%s/%s): '%s'", mm_port_probe_get_port_subsys (MM_PORT_PROBE (l->data)), mm_port_probe_get_port_name (MM_PORT_PROBE (l->data)), inner_error ? inner_error->message : "unknown error"); g_clear_error (&inner_error); } } /* If organizing ports fails, consider the modem invalid */ if (!mm_base_modem_organize_ports (modem, error)) g_clear_object (&modem); } return modem; }