aboutsummaryrefslogtreecommitdiff
path: root/src/mm-generic-cdma.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mm-generic-cdma.c')
-rw-r--r--src/mm-generic-cdma.c2626
1 files changed, 0 insertions, 2626 deletions
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
deleted file mode 100644
index 5397ce95..00000000
--- a/src/mm-generic-cdma.c
+++ /dev/null
@@ -1,2626 +0,0 @@
-/* -*- 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) 2008 - 2009 Novell, Inc.
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "mm-generic-cdma.h"
-#include "mm-modem-cdma.h"
-#include "mm-modem-simple.h"
-#include "mm-at-serial-port.h"
-#include "mm-qcdm-serial-port.h"
-#include "mm-errors.h"
-#include "mm-callback-info.h"
-#include "mm-serial-parsers.h"
-#include "mm-modem-helpers.h"
-#include "libqcdm/src/commands.h"
-#include "libqcdm/src/errors.h"
-#include "mm-log.h"
-
-#define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state"
-
-typedef enum {
- RM_PROTO_ASYNC = 0,
- RM_PROTO_RELAY = 1,
- RM_PROTO_NETWORK_PPP = 2,
- RM_PROTO_NETWORK_SLIP = 3,
- RM_PROTO_STU_III = 4
-} RmProtocol;
-
-
-static void simple_reg_callback (MMModemCdma *modem,
- MMModemCdmaRegistrationState cdma_1x_reg_state,
- MMModemCdmaRegistrationState evdo_reg_state,
- GError *error,
- gpointer user_data);
-
-static void simple_state_machine (MMModem *modem, GError *error, gpointer user_data);
-
-static void update_enabled_state (MMGenericCdma *self,
- gboolean stay_connected,
- MMModemStateReason reason);
-
-static void modem_init (MMModem *modem_class);
-static void modem_cdma_init (MMModemCdma *cdma_class);
-static void modem_simple_init (MMModemSimple *class);
-
-G_DEFINE_TYPE_EXTENDED (MMGenericCdma, mm_generic_cdma, MM_TYPE_MODEM_BASE, 0,
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_CDMA, modem_cdma_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
-
-#define MM_GENERIC_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_CDMA, MMGenericCdmaPrivate))
-
-typedef struct {
- guint32 cdma1x_quality;
- guint32 evdo_quality;
- gboolean valid;
- gboolean evdo_rev0;
- gboolean evdo_revA;
- gboolean reg_try_css;
- gboolean has_spservice;
- gboolean has_speri;
-
- /* Original and current Rm interface protocol */
- RmProtocol orig_crm;
- RmProtocol cur_crm;
-
- guint poll_id;
-
- char *meid;
-
- MMModemCdmaRegistrationState cdma_1x_reg_state;
- MMModemCdmaRegistrationState evdo_reg_state;
-
- guint reg_tries;
- guint reg_retry_id;
- guint reg_state_changed_id;
- MMCallbackInfo *simple_connect_info;
-
- MMAtSerialPort *primary;
- MMAtSerialPort *secondary;
- MMQcdmSerialPort *qcdm;
- MMPort *data;
- gboolean data_opened_at_connect;
-} MMGenericCdmaPrivate;
-
-enum {
- PROP_0,
- PROP_EVDO_REV0,
- PROP_EVDO_REVA,
- PROP_REG_TRY_CSS,
- LAST_PROP
-};
-
-MMModem *
-mm_generic_cdma_new (const char *device,
- const char *driver,
- const char *plugin,
- gboolean evdo_rev0,
- gboolean evdo_revA,
- guint vendor,
- guint product)
-{
- g_return_val_if_fail (device != NULL, NULL);
- g_return_val_if_fail (driver != NULL, NULL);
- g_return_val_if_fail (plugin != NULL, NULL);
-
- return MM_MODEM (g_object_new (MM_TYPE_GENERIC_CDMA,
- MM_MODEM_MASTER_DEVICE, device,
- MM_MODEM_DRIVER, driver,
- MM_MODEM_PLUGIN, plugin,
- MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
- MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
- MM_MODEM_HW_VID, vendor,
- MM_MODEM_HW_PID, product,
- NULL));
-}
-
-/*****************************************************************************/
-
-static void
-check_valid (MMGenericCdma *self)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- gboolean new_valid = FALSE;
-
- if (priv->primary && priv->data)
- new_valid = TRUE;
-
- mm_modem_base_set_valid (MM_MODEM_BASE (self), new_valid);
-}
-
-static void
-get_esn_cb (MMModem *modem,
- const char *result,
- GError *error,
- gpointer user_data)
-{
- if (modem) {
- mm_modem_base_set_equipment_identifier (MM_MODEM_BASE (modem), error ? "" : result);
- mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_CDMA_GET_PRIVATE (modem)->primary));
- check_valid (MM_GENERIC_CDMA (modem));
- }
-}
-
-static void
-initial_esn_check (MMGenericCdma *self)
-{
- GError *error = NULL;
- MMGenericCdmaPrivate *priv;
-
- g_return_if_fail (MM_IS_GENERIC_CDMA (self));
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- g_return_if_fail (priv->primary != NULL);
-
- if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
- /* Make sure echoing is off */
- mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL);
- mm_modem_cdma_get_esn (MM_MODEM_CDMA (self), get_esn_cb, NULL);
- } else {
- g_warning ("%s: failed to open serial port: (%d) %s",
- __func__,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_clear_error (&error);
- check_valid (self);
- }
-}
-
-static void
-get_info_cb (MMModem *modem,
- const char *manufacturer,
- const char *model,
- const char *version,
- GError *error,
- gpointer user_data)
-{
- /* Base class handles saving the info for us */
- if (modem)
- mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_CDMA_GET_PRIVATE (modem)->primary));
-}
-
-static void
-initial_info_check (MMGenericCdma *self)
-{
- GError *error = NULL;
- MMGenericCdmaPrivate *priv;
-
- g_return_if_fail (MM_IS_GENERIC_CDMA (self));
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- g_return_if_fail (priv->primary != NULL);
-
- if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
- /* Make sure echoing is off */
- mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL);
- mm_modem_base_get_card_info (MM_MODEM_BASE (self),
- priv->primary,
- NULL,
- get_info_cb,
- NULL);
- } else {
- g_warning ("%s: failed to open serial port: (%d) %s",
- __func__,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_clear_error (&error);
- }
-}
-
-static gboolean
-owns_port (MMModem *modem, const char *subsys, const char *name)
-{
- return !!mm_modem_base_get_port (MM_MODEM_BASE (modem), subsys, name);
-}
-
-static void
-port_grabbed (MMModemBase *base,
- MMPort *port,
- MMAtPortFlags at_pflags,
- gpointer user_data)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (base);
-
- if (MM_IS_AT_SERIAL_PORT (port)) {
- g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
- mm_at_serial_port_set_flags (MM_AT_SERIAL_PORT (port), at_pflags);
-
- mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port),
- mm_serial_parser_v1_e1_parse,
- mm_serial_parser_v1_e1_new (),
- mm_serial_parser_v1_e1_destroy);
- }
-
- if (MM_GENERIC_CDMA_GET_CLASS (self)->port_grabbed)
- MM_GENERIC_CDMA_GET_CLASS (self)->port_grabbed (self, port, at_pflags, user_data);
-}
-
-static gboolean
-organize_ports (MMModem *modem, GError **error)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- if (!mm_modem_base_organize_ports (MM_MODEM_BASE (modem),
- &priv->primary,
- &priv->secondary,
- &priv->data,
- &priv->qcdm,
- error))
- return FALSE;
-
- /* Let subclasses twiddle ports if they want */
- if (MM_GENERIC_CDMA_GET_CLASS (self)->ports_organized)
- MM_GENERIC_CDMA_GET_CLASS (self)->ports_organized (self, priv->primary);
-
- g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
-
- /* Get the modem's general info */
- initial_info_check (self);
-
- /* Get modem's ESN number */
- initial_esn_check (self);
-
- check_valid (self);
- return TRUE;
-}
-
-static void
-release_port (MMModem *modem, const char *subsys, const char *name)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
- MMPort *port;
-
- port = mm_modem_base_get_port (MM_MODEM_BASE (modem), subsys, name);
- if (!port)
- return;
-
- if (port == (MMPort *) priv->primary) {
- mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
- priv->primary = NULL;
- }
-
- if (port == priv->data) {
- priv->data = NULL;
- g_object_notify (G_OBJECT (modem), MM_MODEM_DATA_DEVICE);
- }
-
- if (port == (MMPort *) priv->secondary) {
- mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
- priv->secondary = NULL;
- }
-
- if (port == (MMPort *) priv->qcdm) {
- mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
- priv->qcdm = NULL;
- }
-
- check_valid (MM_GENERIC_CDMA (modem));
-}
-
-MMAtSerialPort *
-mm_generic_cdma_get_at_port (MMGenericCdma *modem,
- MMAtPortFlags flag)
-{
- MMGenericCdmaPrivate *priv;
-
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (modem), NULL);
-
- /* We only search for a single value even though it's a bitfield */
- g_return_val_if_fail ( flag == MM_AT_PORT_FLAG_NONE
- || flag == MM_AT_PORT_FLAG_PRIMARY
- || flag == MM_AT_PORT_FLAG_SECONDARY
- || flag == MM_AT_PORT_FLAG_PPP, NULL);
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
-
- if (flag == MM_AT_PORT_FLAG_SECONDARY)
- return priv->secondary;
- else if (flag == MM_AT_PORT_FLAG_PRIMARY)
- return priv->primary;
- else if ((flag == MM_AT_PORT_FLAG_PPP) && MM_IS_AT_SERIAL_PORT (priv->data))
- return MM_AT_SERIAL_PORT (priv->data);
-
- return NULL;
-}
-
-MMAtSerialPort *
-mm_generic_cdma_get_best_at_port (MMGenericCdma *self, GError **error)
-{
- MMGenericCdmaPrivate *priv;
-
- g_return_val_if_fail (self != NULL, NULL);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), NULL);
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- if (!mm_port_get_connected (MM_PORT (priv->primary)))
- return priv->primary;
-
- if (!priv->secondary) {
- g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
- "Cannot perform this operation while connected");
- }
-
- return priv->secondary;
-}
-
-MMQcdmSerialPort *
-mm_generic_cdma_get_best_qcdm_port (MMGenericCdma *self, GError **error)
-{
- g_return_val_if_fail (self != NULL, NULL);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), NULL);
-
- return MM_GENERIC_CDMA_GET_PRIVATE (self)->qcdm;
-}
-
-/*****************************************************************************/
-
-void
-mm_generic_cdma_set_1x_registration_state (MMGenericCdma *self,
- MMModemCdmaRegistrationState new_state)
-{
- MMGenericCdmaPrivate *priv;
-
- g_return_if_fail (self != NULL);
- g_return_if_fail (MM_IS_GENERIC_CDMA (self));
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- if (priv->cdma_1x_reg_state != new_state) {
- priv->cdma_1x_reg_state = new_state;
-
- update_enabled_state (self, TRUE, MM_MODEM_STATE_REASON_NONE);
- mm_modem_cdma_emit_registration_state_changed (MM_MODEM_CDMA (self),
- priv->cdma_1x_reg_state,
- priv->evdo_reg_state);
- }
-}
-
-void
-mm_generic_cdma_set_evdo_registration_state (MMGenericCdma *self,
- MMModemCdmaRegistrationState new_state)
-{
- MMGenericCdmaPrivate *priv;
-
- g_return_if_fail (self != NULL);
- g_return_if_fail (MM_IS_GENERIC_CDMA (self));
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- if (priv->evdo_reg_state == new_state)
- return;
-
- /* Don't update EVDO state if the card doesn't support it */
- if ( priv->evdo_rev0
- || priv->evdo_revA
- || (new_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)) {
- priv->evdo_reg_state = new_state;
-
- update_enabled_state (self, TRUE, MM_MODEM_STATE_REASON_NONE);
- mm_modem_cdma_emit_registration_state_changed (MM_MODEM_CDMA (self),
- priv->cdma_1x_reg_state,
- priv->evdo_reg_state);
- }
-}
-
-MMModemCdmaRegistrationState
-mm_generic_cdma_1x_get_registration_state_sync (MMGenericCdma *self)
-{
- g_return_val_if_fail (self != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
-
- return MM_GENERIC_CDMA_GET_PRIVATE (self)->cdma_1x_reg_state;
-}
-
-MMModemCdmaRegistrationState
-mm_generic_cdma_evdo_get_registration_state_sync (MMGenericCdma *self)
-{
- g_return_val_if_fail (self != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
-
- return MM_GENERIC_CDMA_GET_PRIVATE (self)->evdo_reg_state;
-}
-
-/*****************************************************************************/
-
-static void
-periodic_poll_reg_cb (MMModemCdma *modem,
- MMModemCdmaRegistrationState cdma_1x_reg_state,
- MMModemCdmaRegistrationState evdo_reg_state,
- GError *error,
- gpointer user_data)
-{
- /* cached reg state already updated */
-}
-
-static void
-periodic_poll_signal_quality_cb (MMModem *modem,
- guint32 result,
- GError *error,
- gpointer user_data)
-{
- /* cached signal quality already updated */
-}
-
-static gboolean
-periodic_poll_cb (gpointer user_data)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (user_data);
-
- mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (self), periodic_poll_reg_cb, NULL);
- mm_modem_cdma_get_signal_quality (MM_MODEM_CDMA (self), periodic_poll_signal_quality_cb, NULL);
-
- return TRUE;
-}
-
-/*****************************************************************************/
-
-static void
-update_enabled_state (MMGenericCdma *self,
- gboolean stay_connected,
- MMModemStateReason reason)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- /* While connected we don't want registration status changes to change
- * the modem's state away from CONNECTED.
- */
- if (stay_connected && (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_DISCONNECTING))
- return;
-
- if ( priv->cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
- || priv->evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
- mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason);
- else
- mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason);
-}
-
-static void
-registration_cleanup (MMGenericCdma *self, GQuark error_class, guint32 error_num)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- GError *error = NULL;
-
- priv->reg_tries = 0;
-
- if (priv->reg_state_changed_id) {
- g_signal_handler_disconnect (self, priv->reg_state_changed_id);
- priv->reg_state_changed_id = 0;
- }
-
- if (priv->reg_retry_id) {
- g_source_remove (priv->reg_retry_id);
- priv->reg_retry_id = 0;
- }
-
- /* Return an error to any explicit callers of simple_connect */
- if (priv->simple_connect_info && error_class) {
- error = g_error_new_literal (error_class, error_num,
- "Connection attempt terminated");
- simple_state_machine (MM_MODEM (self), error, priv->simple_connect_info);
- g_error_free (error);
- }
- priv->simple_connect_info = NULL;
-}
-
-static void
-get_enable_info_done (MMModem *modem,
- const char *manufacturer,
- const char *model,
- const char *version,
- GError *error,
- gpointer user_data)
-{
- /* Modem base class handles the response for us */
-}
-
-static void
-spservice_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- if (!error) {
- MM_GENERIC_CDMA_GET_PRIVATE (user_data)->has_spservice = TRUE;
-
- /* +SPSERVICE provides a better indicator of registration status than
- * +CSS, which some devices implement inconsistently.
- */
- MM_GENERIC_CDMA_GET_PRIVATE (user_data)->reg_try_css = FALSE;
- }
-}
-
-static void
-speri_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- if (!error)
- MM_GENERIC_CDMA_GET_PRIVATE (user_data)->has_speri = TRUE;
-}
-
-static void
-crm_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- const char *p;
- unsigned long num;
-
- if (error)
- return;
-
- p = mm_strip_tag (response->str, "+CRM:");
- if (p) {
- errno = 0;
- num = strtoul (p, NULL, 10);
- if (num <= 4 && (errno == 0)) {
- MM_GENERIC_CDMA_GET_PRIVATE (user_data)->orig_crm = (guint32) num;
- MM_GENERIC_CDMA_GET_PRIVATE (user_data)->cur_crm = (guint32) num;
- }
- }
-}
-
-static void
-enable_all_done (MMModem *modem, GError *error, gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- if (error)
- info->error = g_error_copy (error);
- else {
- /* Try to enable XON/XOFF flow control */
- mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL);
-
- /* Open up the second port, if one exists */
- if (priv->secondary) {
- if (!mm_serial_port_open (MM_SERIAL_PORT (priv->secondary), &info->error)) {
- g_assert (info->error);
- goto out;
- }
- }
-
- /* Open up the second port, if one exists */
- if (priv->qcdm) {
- if (!mm_serial_port_open (MM_SERIAL_PORT (priv->qcdm), &info->error)) {
- g_assert (info->error);
- goto out;
- }
- }
-
- update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE);
-
- /* Grab device info right away */
- mm_modem_get_info (modem, get_enable_info_done, NULL);
-
- /* Check for support of Sprint-specific phone commands */
- mm_at_serial_port_queue_command (priv->primary, "+SPSERVICE?", 3, spservice_done, self);
- mm_at_serial_port_queue_command (priv->primary, "$SPERI?", 3, speri_done, self);
-
- /* Grab default CRM */
- mm_at_serial_port_queue_command (priv->primary, "+CRM?", 3, crm_done, self);
- }
-
-out:
- if (info->error) {
- mm_modem_set_state (MM_MODEM (info->modem),
- MM_MODEM_STATE_DISABLED,
- MM_MODEM_STATE_REASON_NONE);
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-init_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- /* If the modem has already been removed, return without
- * scheduling callback */
- if (mm_callback_info_check_modem_removed (info))
- return;
-
- if (error) {
- mm_modem_set_state (MM_MODEM (info->modem),
- MM_MODEM_STATE_DISABLED,
- MM_MODEM_STATE_REASON_NONE);
-
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- } else {
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
-
- /* Try enabling better error reporting on CDMA devices, but few
- * actually support +CMEE as it's more of a GSM command.
- */
- mm_at_serial_port_queue_command (port, "+CMEE=1", 3, NULL, NULL);
-
- if (MM_GENERIC_CDMA_GET_CLASS (self)->post_enable)
- MM_GENERIC_CDMA_GET_CLASS (self)->post_enable (self, enable_all_done, info);
- else
- enable_all_done (MM_MODEM (self), NULL, info);
- }
-}
-
-static void
-flash_done (MMSerialPort *port, GError *error, gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- if (error) {
- mm_modem_set_state (MM_MODEM (info->modem),
- MM_MODEM_STATE_DISABLED,
- MM_MODEM_STATE_REASON_NONE);
-
- /* Flash failed for some reason */
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- return;
- }
-
- mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "Z E0 V1 X4 &C1", 3, init_done, user_data);
-}
-
-static void
-enable (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- MMCallbackInfo *info;
-
- info = mm_callback_info_new (modem, callback, user_data);
-
- if (!mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &info->error)) {
- g_assert (info->error);
- mm_callback_info_schedule (info);
- return;
- }
-
- mm_modem_set_state (MM_MODEM (info->modem),
- MM_MODEM_STATE_ENABLING,
- MM_MODEM_STATE_REASON_NONE);
-
- mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 100, FALSE, flash_done, info);
-}
-
-static void
-disable_set_previous_state (MMModem *modem, MMCallbackInfo *info)
-{
- MMModemState prev_state;
-
- /* Reset old state since the operation failed */
- prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_CDMA_PREV_STATE_TAG));
- mm_modem_set_state (modem, prev_state, MM_MODEM_STATE_REASON_NONE);
-}
-
-static void
-disable_all_done (MMModem *modem, GError *error, gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
-
- /* If the modem has already been removed, return without
- * scheduling callback */
- if (!modem || mm_callback_info_check_modem_removed (info))
- return;
-
- if (error) {
- info->error = g_error_copy (error);
- disable_set_previous_state (modem, info);
- } else {
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- mm_serial_port_close_force (MM_SERIAL_PORT (priv->primary));
- mm_modem_set_state (modem, MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE);
-
- priv->cdma_1x_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
- priv->evdo_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-disable_flash_done (MMSerialPort *port,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- MMGenericCdma *self;
-
- /* 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);
-
- disable_set_previous_state (info->modem, info);
- mm_callback_info_schedule (info);
- return;
- }
-
- self = MM_GENERIC_CDMA (info->modem);
-
- if (MM_GENERIC_CDMA_GET_CLASS (self)->post_disable)
- MM_GENERIC_CDMA_GET_CLASS (self)->post_disable (self, disable_all_done, info);
- else
- disable_all_done (MM_MODEM (self), NULL, info);
-}
-
-static void
-disable (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- MMCallbackInfo *info;
- MMModemState state;
-
- /* Tear down any ongoing registration */
- registration_cleanup (self, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
-
- info = mm_callback_info_new (modem, callback, user_data);
-
- /* Cache the previous state so we can reset it if the operation fails */
- state = mm_modem_get_state (modem);
- mm_callback_info_set_data (info,
- MM_GENERIC_CDMA_PREV_STATE_TAG,
- GUINT_TO_POINTER (state),
- NULL);
-
- /* Close auxiliary serial ports */
- if (priv->secondary)
- mm_serial_port_close_force (MM_SERIAL_PORT (priv->secondary));
- if (priv->qcdm)
- mm_serial_port_close_force (MM_SERIAL_PORT (priv->qcdm));
-
- mm_modem_set_state (MM_MODEM (info->modem),
- MM_MODEM_STATE_DISABLING,
- MM_MODEM_STATE_REASON_NONE);
-
- if (mm_port_get_connected (MM_PORT (priv->primary)))
- mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, TRUE, disable_flash_done, info);
- else
- disable_flash_done (MM_SERIAL_PORT (priv->primary), NULL, info);
-}
-
-static void
-dial_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- /* 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);
- update_enabled_state (MM_GENERIC_CDMA (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE);
- } else {
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- /* Clear reg tries; we're obviously registered by this point */
- registration_cleanup (self, 0, 0);
-
- mm_port_set_connected (priv->data, TRUE);
- mm_modem_set_state (info->modem, MM_MODEM_STATE_CONNECTED, MM_MODEM_STATE_REASON_NONE);
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-connect (MMModem *modem,
- const char *number,
- MMModemFn callback,
- gpointer user_data)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
- MMCallbackInfo *info;
- char *command;
- MMAtSerialPort *dial_port;
-
- info = mm_callback_info_new (modem, callback, user_data);
-
- /* Dial port might not be the primary port*/
- priv->data_opened_at_connect = FALSE;
- dial_port = priv->primary;
- if (MM_IS_AT_SERIAL_PORT (priv->data)) {
- dial_port = MM_AT_SERIAL_PORT (priv->data);
-
- if (!mm_serial_port_open (MM_SERIAL_PORT (dial_port), &info->error)) {
- g_warning ("%s: failed to open dial port: (%d) %s",
- __func__,
- info->error ? info->error->code : -1,
- info->error && info->error->message ? info->error->message : "(unknown)");
- mm_callback_info_schedule (info);
- return;
- }
- priv->data_opened_at_connect = TRUE;
- }
-
- mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
-
- command = g_strconcat ("DT", number, NULL);
- mm_at_serial_port_queue_command (dial_port, command, 90, dial_done, info);
- g_free (command);
-}
-
-static void
-disconnect_flash_done (MMSerialPort *port,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericCdma *self;
- MMGenericCdmaPrivate *priv;
- MMModemState prev_state;
-
- /* If the modem has already been removed, return without
- * scheduling callback */
- if (mm_callback_info_check_modem_removed (info))
- return;
-
- self = MM_GENERIC_CDMA (info->modem);
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- if (error) {
- info->error = g_error_copy (error);
-
- /* Reset old state since the operation failed */
- prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_CDMA_PREV_STATE_TAG));
- mm_modem_set_state (MM_MODEM (info->modem),
- prev_state,
- MM_MODEM_STATE_REASON_NONE);
- } else {
- mm_port_set_connected (priv->data, FALSE);
- update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE);
- }
-
- /* Balance any open from connect(); subclasses may not use the generic
- * class' connect function and so the dial port may not have been
- * opened at all.
- */
- if (priv->data_opened_at_connect) {
- if (MM_IS_AT_SERIAL_PORT (port))
- mm_serial_port_close (port);
- priv->data_opened_at_connect = FALSE;
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-disconnect (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
- MMCallbackInfo *info;
- MMModemState state;
- MMAtSerialPort *dial_port;
-
- g_return_if_fail (priv->primary != NULL);
-
- info = mm_callback_info_new (modem, callback, user_data);
-
- /* Cache the previous state so we can reset it if the operation fails */
- state = mm_modem_get_state (modem);
- mm_callback_info_set_data (info,
- MM_GENERIC_CDMA_PREV_STATE_TAG,
- GUINT_TO_POINTER (state),
- NULL);
-
- mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE);
-
- dial_port = priv->primary;
- if (MM_IS_AT_SERIAL_PORT (priv->data))
- dial_port = MM_AT_SERIAL_PORT (priv->data);
-
- mm_serial_port_flash (MM_SERIAL_PORT (dial_port), 1000, TRUE, disconnect_flash_done, info);
-}
-
-static void
-get_card_info (MMModem *modem,
- MMModemInfoFn callback,
- gpointer user_data)
-{
- MMAtSerialPort *port;
- GError *error = NULL;
-
- port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &error);
- mm_modem_base_get_card_info (MM_MODEM_BASE (modem), port, error, callback, user_data);
- g_clear_error (&error);
-}
-
-/*****************************************************************************/
-
-void
-mm_generic_cdma_update_cdma1x_quality (MMGenericCdma *self, guint32 quality)
-{
- MMGenericCdmaPrivate *priv;
-
- g_return_if_fail (MM_IS_GENERIC_CDMA (self));
- g_return_if_fail (quality >= 0 && quality <= 100);
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- if (priv->cdma1x_quality != quality) {
- priv->cdma1x_quality = quality;
- mm_modem_cdma_emit_signal_quality_changed (MM_MODEM_CDMA (self), quality);
- }
-}
-
-void
-mm_generic_cdma_update_evdo_quality (MMGenericCdma *self, guint32 quality)
-{
- MMGenericCdmaPrivate *priv;
-
- g_return_if_fail (MM_IS_GENERIC_CDMA (self));
- g_return_if_fail (quality >= 0 && quality <= 100);
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- if (priv->evdo_quality != quality) {
- priv->evdo_quality = quality;
- // FIXME: emit a signal
- }
-}
-
-#define CSQ2_TRIED "csq?-tried"
-
-static void
-get_signal_quality_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMGenericCdmaPrivate *priv;
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- /* If the modem has already been removed, return without
- * scheduling callback */
- if (mm_callback_info_check_modem_removed (info))
- return;
-
- if (error) {
- if (mm_callback_info_get_data (info, CSQ2_TRIED))
- info->error = g_error_copy (error);
- else {
- /* Some modems want +CSQ, others want +CSQ?, and some of both types
- * will return ERROR if they don't get the command they want. So
- * try the other command if the first one fails.
- */
- mm_callback_info_set_data (info, CSQ2_TRIED, GUINT_TO_POINTER (1), NULL);
- mm_at_serial_port_queue_command (port, "+CSQ?", 3, get_signal_quality_done, info);
- return;
- }
- } else {
- const char *reply = response->str;
- int quality, ber;
-
- /* Got valid reply */
- if (!strncmp (reply, "+CSQ: ", 6))
- reply += 6;
-
- if (sscanf (reply, "%d, %d", &quality, &ber)) {
- /* 99 means unknown/no service */
- if (quality == 99) {
- info->error = g_error_new_literal (MM_MOBILE_ERROR,
- MM_MOBILE_ERROR_NO_NETWORK,
- "No service");
- } else {
- /* Normalize the quality */
- quality = CLAMP (quality, 0, 31) * 100 / 31;
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
- mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
- if (priv->cdma1x_quality != quality) {
- priv->cdma1x_quality = quality;
- mm_modem_cdma_emit_signal_quality_changed (MM_MODEM_CDMA (info->modem), quality);
- }
- }
- } else
- info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "%s", "Could not parse signal quality results");
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-qcdm_pilot_sets_cb (MMQcdmSerialPort *port,
- GByteArray *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- MMGenericCdmaPrivate *priv;
- QcdmResult *result;
- guint32 num = 0, quality = 0, i;
- float best_db = -28;
- int err = QCDM_SUCCESS;
-
- if (error) {
- info->error = g_error_copy (error);
- goto done;
- }
-
- priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
-
- /* Parse the response */
- result = qcdm_cmd_pilot_sets_result ((const char *) response->data, response->len, &err);
- if (!result) {
- g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Failed to parse pilot sets command result: %d", err);
- goto done;
- }
-
- qcdm_cmd_pilot_sets_result_get_num (result, QCDM_CMD_PILOT_SETS_TYPE_ACTIVE, &num);
- for (i = 0; i < num; i++) {
- guint32 pn_offset = 0, ecio = 0;
- float db = 0;
-
- qcdm_cmd_pilot_sets_result_get_pilot (result,
- QCDM_CMD_PILOT_SETS_TYPE_ACTIVE,
- i,
- &pn_offset,
- &ecio,
- &db);
- best_db = MAX (db, best_db);
- }
- qcdm_result_unref (result);
-
- if (num > 0) {
- #define BEST_ECIO 3
- #define WORST_ECIO 25
-
- /* EC/IO dB ranges from roughly 0 to -31 dB. Lower == worse. We
- * really only care about -3 to -25 dB though, since that's about what
- * you'll see in real-world usage.
- */
- best_db = CLAMP (ABS (best_db), BEST_ECIO, WORST_ECIO) - BEST_ECIO;
- quality = (guint32) (100 - (best_db * 100 / (WORST_ECIO - BEST_ECIO)));
- }
-
- mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
-
- if (priv->cdma1x_quality != quality) {
- priv->cdma1x_quality = quality;
- mm_modem_cdma_emit_signal_quality_changed (MM_MODEM_CDMA (info->modem), quality);
- }
-
-done:
- mm_callback_info_schedule (info);
-}
-
-static void
-get_signal_quality (MMModemCdma *modem,
- MMModemUIntFn callback,
- gpointer user_data)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
- MMCallbackInfo *info;
- MMAtSerialPort *at_port;
-
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
-
- at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error);
- if (!at_port && !priv->qcdm) {
- mm_dbg ("Returning saved signal quality %d", priv->cdma1x_quality);
- mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->cdma1x_quality), NULL);
- mm_callback_info_schedule (info);
- return;
- }
- g_clear_error (&info->error);
-
- if (at_port)
- mm_at_serial_port_queue_command (at_port, "+CSQ", 3, get_signal_quality_done, info);
- else if (priv->qcdm) {
- GByteArray *pilot_sets;
-
- /* Use CDMA1x pilot EC/IO if we can */
- pilot_sets = g_byte_array_sized_new (25);
- pilot_sets->len = qcdm_cmd_pilot_sets_new ((char *) pilot_sets->data, 25);
- g_assert (pilot_sets->len);
- mm_qcdm_serial_port_queue_command (priv->qcdm, pilot_sets, 3, qcdm_pilot_sets_cb, info);
- }
-}
-
-static void
-get_string_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- const char *p;
-
- /* 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);
- else {
- p = mm_strip_tag (response->str, "+GSN:");
- mm_callback_info_set_result (info, g_strdup (p), g_free);
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-get_esn (MMModemCdma *modem,
- MMModemStringFn callback,
- gpointer user_data)
-{
- MMCallbackInfo *info;
- MMAtSerialPort *port;
-
- info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
-
- port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error);
- if (!port) {
- mm_callback_info_schedule (info);
- return;
- }
-
- mm_at_serial_port_queue_command_cached (port, "+GSN", 3, get_string_done, info);
-}
-
-static void
-serving_system_invoke (MMCallbackInfo *info)
-{
- MMModemCdmaServingSystemFn callback = (MMModemCdmaServingSystemFn) info->callback;
-
- callback (MM_MODEM_CDMA (info->modem),
- GPOINTER_TO_UINT (mm_callback_info_get_data (info, "class")),
- (unsigned char) GPOINTER_TO_UINT (mm_callback_info_get_data (info, "band")),
- GPOINTER_TO_UINT (mm_callback_info_get_data (info, "sid")),
- info->error,
- info->user_data);
-}
-
-static int
-normalize_class (const char *orig_class)
-{
- char class;
-
- g_return_val_if_fail (orig_class != NULL, '0');
-
- class = toupper (orig_class[0]);
-
- /* Cellular (850MHz) */
- if (class == '1' || class == 'C')
- return 1;
- /* PCS (1900MHz) */
- if (class == '2' || class == 'P')
- return 2;
-
- /* Unknown/not registered */
- return 0;
-}
-
-static char
-normalize_band (const char *long_band, int *out_class)
-{
- char band;
-
- g_return_val_if_fail (long_band != NULL, 'Z');
-
- /* There are two response formats for the band; one includes the band
- * class and the other doesn't. For modems that include the band class
- * (ex Novatel S720) you'll see "Px" or "Cx" depending on whether the modem
- * is registered on a PCS/1900 (P) or Cellular/850 (C) system.
- */
- band = toupper (long_band[0]);
-
- /* Possible band class in first position; return it */
- if (band == 'C' || band == 'P') {
- char tmp[2] = { band, '\0' };
-
- *out_class = normalize_class (tmp);
- band = toupper (long_band[1]);
- }
-
- /* normalize to A - F, and Z */
- if (band >= 'A' && band <= 'F')
- return band;
-
- /* Unknown/not registered */
- return 'Z';
-}
-
-static int
-convert_sid (const char *sid)
-{
- long int tmp_sid;
-
- g_return_val_if_fail (sid != NULL, 99999);
-
- errno = 0;
- tmp_sid = strtol (sid, NULL, 10);
- if ((errno == EINVAL) || (errno == ERANGE))
- return 99999;
- else if (tmp_sid < G_MININT || tmp_sid > G_MAXINT)
- return 99999;
-
- return (int) tmp_sid;
-}
-
-static GError *
-new_css_no_service_error (void)
-{
- /* NOTE: update reg_state_css_response() if this error changes */
- return g_error_new_literal (MM_MOBILE_ERROR,
- MM_MOBILE_ERROR_NO_NETWORK,
- "No service");
-}
-
-static void
-serving_system_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- char *reply;
- int class = 0, sid = 99999, num;
- unsigned char band = 'Z';
- gboolean success = FALSE;
-
- /* 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;
- }
-
- reply = response->str;
- if (strstr (reply, "+CSS: "))
- reply += 6;
-
- num = sscanf (reply, "? , %d", &sid);
- if (num == 1) {
- /* UTStarcom and Huawei modems that use IS-707-A format; note that
- * this format obviously doesn't have other indicators like band and
- * class and thus SID 0 will be reported as "no service" (see below).
- */
- class = 0;
- band = 'Z';
- success = TRUE;
- } else {
- GRegex *r;
- GMatchInfo *match_info;
- int override_class = 0;
-
- /* Format is "<band_class>,<band>,<sid>" */
- r = g_regex_new ("\\s*([^,]*?)\\s*,\\s*([^,]*?)\\s*,\\s*(\\d+)", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- if (!r) {
- info->error = g_error_new_literal (MM_MODEM_ERROR,
- MM_MODEM_ERROR_GENERAL,
- "Could not parse Serving System results (regex creation failed).");
- goto out;
- }
-
- g_regex_match (r, reply, 0, &match_info);
- if (g_match_info_get_match_count (match_info) >= 3) {
- char *str;
-
- /* band class */
- str = g_match_info_fetch (match_info, 1);
- class = normalize_class (str);
- g_free (str);
-
- /* band */
- str = g_match_info_fetch (match_info, 2);
- band = normalize_band (str, &override_class);
- if (override_class)
- class = override_class;
- g_free (str);
-
- /* sid */
- str = g_match_info_fetch (match_info, 3);
- sid = convert_sid (str);
- g_free (str);
-
- success = TRUE;
- }
-
- g_match_info_free (match_info);
- g_regex_unref (r);
- }
-
- if (success) {
- gboolean class_ok = FALSE, band_ok = FALSE;
-
- /* Normalize the SID */
- if (sid < 0 || sid > 32767)
- sid = 99999;
-
- if (class == 1 || class == 2)
- class_ok = TRUE;
- if (band != 'Z')
- band_ok = TRUE;
-
- /* Return 'no service' if none of the elements of the +CSS response
- * indicate that the modem has service. Note that this allows SID 0
- * when at least one of the other elements indicates service.
- * Normally we'd treat SID 0 as 'no service' but some modems
- * (Sierra 5725) sometimes return SID 0 even when registered.
- */
- if (sid == 0 && !class_ok && !band_ok)
- sid = 99999;
-
- /* 99999 means unknown/no service */
- if (sid == 99999)
- info->error = new_css_no_service_error ();
- else {
- mm_callback_info_set_data (info, "class", GUINT_TO_POINTER (class), NULL);
- mm_callback_info_set_data (info, "band", GUINT_TO_POINTER ((guint32) band), NULL);
- mm_callback_info_set_data (info, "sid", GUINT_TO_POINTER (sid), NULL);
- }
- } else {
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Could not parse Serving System results.");
- }
-
- out:
- mm_callback_info_schedule (info);
-}
-
-static void
-legacy_get_serving_system (MMGenericCdma *self, MMCallbackInfo *info)
-{
- MMAtSerialPort *port;
-
- port = mm_generic_cdma_get_best_at_port (self, &info->error);
- if (port)
- mm_at_serial_port_queue_command (port, "+CSS?", 3, serving_system_done, info);
- else
- mm_callback_info_schedule (info);
-}
-
-static void
-cdma_status_cb (MMQcdmSerialPort *port,
- GByteArray *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- QcdmResult *result;
- guint32 sid, rxstate;
- int err = QCDM_SUCCESS;
-
- if (error)
- goto error;
-
- /* Parse the response */
- result = qcdm_cmd_cdma_status_result ((const char *) response->data, response->len, &err);
- if (!result) {
- g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Failed to parse cdma status command result: %d", err);
- goto error;
- }
-
- qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_RX_STATE, &rxstate);
- qcdm_result_get_u32 (result, QCDM_CMD_CDMA_STATUS_ITEM_SID, &sid);
- qcdm_result_unref (result);
-
- if (rxstate == QCDM_CMD_CDMA_STATUS_RX_STATE_ENTERING_CDMA)
- info->error = new_css_no_service_error ();
- else {
- mm_callback_info_set_data (info, "class", GUINT_TO_POINTER (0), NULL);
- mm_callback_info_set_data (info, "band", GUINT_TO_POINTER ((guint32) 'Z'), NULL);
- mm_callback_info_set_data (info, "sid", GUINT_TO_POINTER (sid), NULL);
- }
-
- mm_callback_info_schedule (info);
- return;
-
-error:
- /* If there was some error, fall back to use +CSS like we did before QCDM */
- legacy_get_serving_system (MM_GENERIC_CDMA (info->modem), info);
-}
-
-static void
-get_serving_system (MMModemCdma *modem,
- MMModemCdmaServingSystemFn callback,
- gpointer user_data)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- MMCallbackInfo *info;
-
- info = mm_callback_info_new_full (MM_MODEM (modem),
- serving_system_invoke,
- G_CALLBACK (callback),
- user_data);
-
- if (priv->qcdm) {
- GByteArray *cdma_status;
-
- cdma_status = g_byte_array_sized_new (25);
- cdma_status->len = qcdm_cmd_cdma_status_new ((char *) cdma_status->data, 25);
- g_assert (cdma_status->len);
- mm_qcdm_serial_port_queue_command (priv->qcdm, cdma_status, 3, cdma_status_cb, info);
- } else
- legacy_get_serving_system (self, info);
-}
-
-/*****************************************************************************/
-
-/* Registration state stuff */
-
-#define CDMA_1X_STATE_TAG "cdma-1x-reg-state"
-#define EVDO_STATE_TAG "evdo-reg-state"
-
-MMModemCdmaRegistrationState
-mm_generic_cdma_query_reg_state_get_callback_1x_state (MMCallbackInfo *info)
-{
- g_return_val_if_fail (info != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- g_return_val_if_fail (info->modem != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (info->modem), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
-
- return GPOINTER_TO_UINT (mm_callback_info_get_data (info, CDMA_1X_STATE_TAG));
-}
-
-void
-mm_generic_cdma_query_reg_state_set_callback_1x_state (MMCallbackInfo *info,
- MMModemCdmaRegistrationState new_state)
-{
- g_return_if_fail (info != NULL);
- g_return_if_fail (info->modem != NULL);
- g_return_if_fail (MM_IS_GENERIC_CDMA (info->modem));
-
- mm_callback_info_set_data (info, CDMA_1X_STATE_TAG, GUINT_TO_POINTER (new_state), NULL);
-}
-
-MMModemCdmaRegistrationState
-mm_generic_cdma_query_reg_state_get_callback_evdo_state (MMCallbackInfo *info)
-{
- g_return_val_if_fail (info != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- g_return_val_if_fail (info->modem != NULL, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (info->modem), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
-
- return GPOINTER_TO_UINT (mm_callback_info_get_data (info, EVDO_STATE_TAG));
-}
-
-void
-mm_generic_cdma_query_reg_state_set_callback_evdo_state (MMCallbackInfo *info,
- MMModemCdmaRegistrationState new_state)
-{
- g_return_if_fail (info != NULL);
- g_return_if_fail (info->modem != NULL);
- g_return_if_fail (MM_IS_GENERIC_CDMA (info->modem));
-
- mm_callback_info_set_data (info, EVDO_STATE_TAG, GUINT_TO_POINTER (new_state), NULL);
-}
-
-static void
-registration_state_invoke (MMCallbackInfo *info)
-{
- MMModemCdmaRegistrationStateFn callback = (MMModemCdmaRegistrationStateFn) info->callback;
-
- /* note: This is the MMModemCdma interface callback */
- callback (MM_MODEM_CDMA (info->modem),
- mm_generic_cdma_query_reg_state_get_callback_1x_state (info),
- mm_generic_cdma_query_reg_state_get_callback_evdo_state (info),
- info->error,
- info->user_data);
-}
-
-MMCallbackInfo *
-mm_generic_cdma_query_reg_state_callback_info_new (MMGenericCdma *self,
- MMModemCdmaRegistrationState cur_cdma_state,
- MMModemCdmaRegistrationState cur_evdo_state,
- MMModemCdmaRegistrationStateFn callback,
- gpointer user_data)
-{
- MMCallbackInfo *info;
-
- g_return_val_if_fail (self != NULL, NULL);
- g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), NULL);
- g_return_val_if_fail (callback != NULL, NULL);
-
- info = mm_callback_info_new_full (MM_MODEM (self),
- registration_state_invoke,
- G_CALLBACK (callback),
- user_data);
-
- /* Fill with current state */
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, cur_cdma_state);
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, cur_evdo_state);
- return info;
-}
-
-static void
-set_callback_1x_state_helper (MMCallbackInfo *info,
- MMModemCdmaRegistrationState new_state)
-{
- if (info->modem) {
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
-
- mm_generic_cdma_set_1x_registration_state (self, new_state);
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, priv->cdma_1x_reg_state);
- }
-}
-
-static void
-set_callback_evdo_state_helper (MMCallbackInfo *info,
- MMModemCdmaRegistrationState new_state)
-{
- if (info->modem) {
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
-
- mm_generic_cdma_set_evdo_registration_state (self, new_state);
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, priv->evdo_reg_state);
- }
-}
-
-static void
-subclass_reg_query_done (MMModemCdma *cdma,
- MMModemCdmaRegistrationState cdma_reg_state,
- MMModemCdmaRegistrationState evdo_reg_state,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- /* 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);
- else {
- /* Set final registration state */
- set_callback_1x_state_helper (info, cdma_reg_state);
- set_callback_evdo_state_helper (info, evdo_reg_state);
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-reg_query_speri_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- gboolean roam = FALSE;
- const char *p;
-
- /* If the modem has already been removed, return without
- * scheduling callback */
- if (mm_callback_info_check_modem_removed (info))
- return;
-
- if (error)
- goto done;
-
- p = mm_strip_tag (response->str, "$SPERI:");
- if (!p || !mm_cdma_parse_eri (p, &roam, NULL, NULL))
- goto done;
-
- if (roam) {
- /* Change the 1x and EVDO registration states to roaming if they were
- * anything other than UNKNOWN.
- */
- if (mm_generic_cdma_query_reg_state_get_callback_1x_state (info))
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING);
-
- if (mm_generic_cdma_query_reg_state_get_callback_evdo_state (info))
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING);
- } else {
- /* Change 1x and/or EVDO registration state to home if home/roaming wasn't previously known */
- if (mm_generic_cdma_query_reg_state_get_callback_1x_state (info) == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED)
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
-
- if (mm_generic_cdma_query_reg_state_get_callback_evdo_state (info) == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED)
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
- }
-
-done:
- mm_callback_info_schedule (info);
-}
-
-static void
-reg_query_spservice_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- MMModemCdmaRegistrationState cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
- MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
-
- /* 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);
- else if (mm_cdma_parse_spservice_response (response->str, &cdma_state, &evdo_state)) {
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, cdma_state);
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, evdo_state);
-
- if (MM_GENERIC_CDMA_GET_PRIVATE (info->modem)->has_speri) {
- /* Get roaming status to override generic registration state */
- mm_at_serial_port_queue_command (port, "$SPERI?", 3, reg_query_speri_done, info);
- return;
- }
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-real_query_registration_state (MMGenericCdma *self,
- MMModemCdmaRegistrationState cur_cdma_state,
- MMModemCdmaRegistrationState cur_evdo_state,
- MMModemCdmaRegistrationStateFn callback,
- gpointer user_data)
-{
- MMCallbackInfo *info;
- MMAtSerialPort *port;
-
- /* Seed this CallbackInfo with any previously determined registration state */
- info = mm_generic_cdma_query_reg_state_callback_info_new (self,
- cur_cdma_state,
- cur_evdo_state,
- callback,
- user_data);
-
- port = mm_generic_cdma_get_best_at_port (self, &info->error);
- if (!port) {
- /* If we can't get an AT port, but less specific registration checks
- * were successful, just use that and don't return an error.
- */
- if ( cur_cdma_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
- || cur_evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
- g_clear_error (&info->error);
- mm_callback_info_schedule (info);
- return;
- }
-
- if (MM_GENERIC_CDMA_GET_PRIVATE (self)->has_spservice) {
- /* Try Sprint-specific commands */
- mm_at_serial_port_queue_command (port, "+SPSERVICE?", 3, reg_query_spservice_done, info);
- } else {
- /* Assume we're at least registered on the 1x network if we passed
- * +CAD, +CSS, and QCDM Call Manager checking. But don't override a
- * more specific registration state passed from a caller.
- */
- if (cur_cdma_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
-
- /* Don't touch EVDO state; it's already either UNKNOWN, or been set
- * by generic checking earlier.
- */
-
- mm_callback_info_schedule (info);
- }
-}
-
-static void
-reg_state_css_response (MMModemCdma *cdma,
- guint32 class,
- unsigned char band,
- guint32 sid,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- /* We'll get an error if the SID isn't valid, so detect that and
- * report unknown registration state.
- */
- if (error) {
- if (g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_NO_NETWORK)) {
- set_callback_1x_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- set_callback_evdo_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- } else {
- /* Some other error parsing CSS results */
- info->error = g_error_copy (error);
- }
- mm_callback_info_schedule (info);
- } else {
- /* We're registered on the CDMA 1x network at least, but let subclasses
- * do more specific registration checking.
- */
- MM_GENERIC_CDMA_GET_CLASS (cdma)->query_registration_state (MM_GENERIC_CDMA (info->modem),
- MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED,
- MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
- subclass_reg_query_done,
- info);
- }
-}
-
-static void
-get_analog_digital_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- const char *reply;
- long int int_cad;
-
- /* 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 error;
- }
-
- /* Strip any leading command tag and spaces */
- reply = mm_strip_tag (response->str, "+CAD:");
-
- errno = 0;
- int_cad = strtol (reply, NULL, 10);
- if ((errno == EINVAL) || (errno == ERANGE)) {
- info->error = g_error_new_literal (MM_MODEM_ERROR,
- MM_MODEM_ERROR_GENERAL,
- "Failed to parse +CAD response");
- goto error;
- }
-
- if (int_cad == 1) { /* 1 == CDMA service */
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem);
-
- /* Now that we have some sort of service, check if the the device is
- * registered on the network.
- */
-
- /* Some devices key the AT+CSS? response off the 1X state, but if the
- * device has EVDO service but no 1X service, then reading AT+CSS? will
- * error out too early. Let subclasses that know that their AT+CSS?
- * response is wrong in this case handle more specific registration
- * themselves; if they do, they'll set priv->reg_try_css to FALSE.
- */
- if (priv->reg_try_css) {
- get_serving_system (MM_MODEM_CDMA (info->modem),
- reg_state_css_response,
- info);
- } else {
- /* Subclass knows that AT+CSS? will respond incorrectly to EVDO
- * state, so skip AT+CSS? query.
- */
- MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state (MM_GENERIC_CDMA (info->modem),
- MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
- MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
- subclass_reg_query_done,
- info);
- }
- return;
- } else {
- /* No service */
- set_callback_1x_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- set_callback_evdo_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- }
-
-error:
- mm_callback_info_schedule (info);
-}
-
-static void
-reg_hdrstate_cb (MMQcdmSerialPort *port,
- GByteArray *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- QcdmResult *result = NULL;
- guint32 sysmode;
- MMModemCdmaRegistrationState cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
- MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
- MMAtSerialPort *at_port;
- gboolean evdo_registered = FALSE;
-
- if (error)
- goto error;
-
- sysmode = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "sysmode"));
-
- /* Get HDR subsystem state to determine EVDO registration when in 1X mode */
- result = qcdm_cmd_hdr_subsys_state_info_result ((const char *) response->data,
- response->len,
- NULL);
- if (result) {
- guint8 session_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_SESSION_STATE_CLOSED;
- guint8 almp_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_INACTIVE;
- guint8 hybrid_mode = 0;
-
- if ( qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, &session_state)
- && qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, &almp_state)
- && qcdm_result_get_u8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, &hybrid_mode)) {
-
- /* EVDO state is registered if the HDR subsystem is registered, and
- * we're in hybrid mode, and the Call Manager system mode is
- * CDMA.
- */
- if ( hybrid_mode
- && session_state == QCDM_CMD_HDR_SUBSYS_STATE_INFO_SESSION_STATE_OPEN
- && ( almp_state == QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_IDLE
- || almp_state == QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_CONNECTED))
- evdo_registered = TRUE;
- }
-
- qcdm_result_unref (result);
- }
-
- switch (sysmode) {
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_CDMA:
- cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
- if (evdo_registered)
- evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
- break;
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR:
- evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
- break;
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_AMPS:
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_NO_SERVICE:
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA:
- default:
- break;
- }
-
- if (cdma_state || evdo_state) {
- /* Device is registered to something; see if the subclass has a
- * better idea of whether we're roaming or not and what the
- * access technology is.
- */
- if (MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state) {
- MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state (MM_GENERIC_CDMA (info->modem),
- cdma_state,
- evdo_state,
- subclass_reg_query_done,
- info);
- return;
- }
- }
-
- set_callback_1x_state_helper (info, cdma_state);
- set_callback_evdo_state_helper (info, evdo_state);
- mm_callback_info_schedule (info);
- return;
-
-error:
- /* If there was some error, fall back to use +CAD like we did before QCDM */
- at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (info->modem), &info->error);
- if (at_port)
- mm_at_serial_port_queue_command (at_port, "+CAD?", 3, get_analog_digital_done, info);
- else
- mm_callback_info_schedule (info);
-}
-
-static void
-reg_cmstate_cb (MMQcdmSerialPort *port,
- GByteArray *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = user_data;
- MMAtSerialPort *at_port = NULL;
- QcdmResult *result = NULL;
- guint32 opmode = 0, sysmode = 0;
- int err = QCDM_SUCCESS;
-
- /* Parse the response */
- if (!error)
- result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &err);
-
- if (!result) {
- /* If there was some error, fall back to use +CAD like we did before QCDM */
- if (info->modem)
- at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (info->modem), &info->error);
- else {
- g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Failed to parse CM subsys state info command result: %d", err);
- }
-
- if (at_port)
- mm_at_serial_port_queue_command (at_port, "+CAD?", 3, get_analog_digital_done, info);
- else
- mm_callback_info_schedule (info);
- return;
- }
-
- qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &opmode);
- qcdm_result_get_u32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &sysmode);
- qcdm_result_unref (result);
-
- if (opmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE) {
- GByteArray *hdrstate;
-
- mm_callback_info_set_data (info, "sysmode", GUINT_TO_POINTER (sysmode), NULL);
-
- /* Get HDR subsystem state */
- hdrstate = g_byte_array_sized_new (25);
- hdrstate->len = qcdm_cmd_hdr_subsys_state_info_new ((char *) hdrstate->data, 25);
- g_assert (hdrstate->len);
- mm_qcdm_serial_port_queue_command (port, hdrstate, 3, reg_hdrstate_cb, info);
- } else {
- /* No service */
- set_callback_1x_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- set_callback_evdo_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- mm_callback_info_schedule (info);
- }
-}
-
-static void
-get_registration_state (MMModemCdma *modem,
- MMModemCdmaRegistrationStateFn callback,
- gpointer user_data)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
- MMCallbackInfo *info;
- MMAtSerialPort *port;
-
- info = mm_generic_cdma_query_reg_state_callback_info_new (MM_GENERIC_CDMA (modem),
- MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
- MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
- callback,
- user_data);
-
- port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error);
- if (!port && !priv->qcdm) {
- mm_dbg ("Returning saved registration states: 1x: %d EVDO: %d",
- priv->cdma_1x_reg_state, priv->evdo_reg_state);
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, priv->cdma_1x_reg_state);
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, priv->evdo_reg_state);
- mm_callback_info_schedule (info);
- return;
- }
- g_clear_error (&info->error);
-
- /* Use QCDM for Call Manager state or HDR state before trying CAD, since
- * CAD doesn't always reflect the state of the HDR radio's registration
- * status.
- */
- if (priv->qcdm) {
- GByteArray *cmstate;
-
- cmstate = g_byte_array_sized_new (25);
- cmstate->len = qcdm_cmd_cm_subsys_state_info_new ((char *) cmstate->data, 25);
- g_assert (cmstate->len);
- mm_qcdm_serial_port_queue_command (priv->qcdm, cmstate, 3, reg_cmstate_cb, info);
- } else
- mm_at_serial_port_queue_command (port, "+CAD?", 3, get_analog_digital_done, info);
-}
-
-/*****************************************************************************/
-
-static void
-set_rm_proto_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- if (mm_callback_info_check_modem_removed (info) == FALSE) {
- if (error)
- info->error = g_error_copy (error);
-
- mm_callback_info_schedule (info);
- }
-}
-
-static void
-mm_generic_cdma_set_rm_protocol (MMGenericCdma *self,
- RmProtocol proto,
- MMModemFn callback,
- gpointer user_data)
-{
- MMCallbackInfo *info;
- MMAtSerialPort *port;
- char *cmd;
-
- info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
-
- port = mm_generic_cdma_get_best_at_port (self, &info->error);
- if (!port) {
- mm_callback_info_schedule (info);
- return;
- }
- g_clear_error (&info->error);
-
- if (proto < RM_PROTO_ASYNC || proto > RM_PROTO_STU_III) {
- g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Invalid Rm interface protocol %d",
- proto);
- mm_callback_info_schedule (info);
- return;
- }
-
- cmd = g_strdup_printf ("+CRM=%d", proto);
- mm_at_serial_port_queue_command (port, cmd, 3, set_rm_proto_done, info);
- g_free (cmd);
-}
-
-/*****************************************************************************/
-/* MMModemSimple interface */
-
-typedef enum {
- SIMPLE_STATE_BEGIN = 0,
- SIMPLE_STATE_ENABLE,
- SIMPLE_STATE_REGISTER,
- SIMPLE_STATE_PRE_CONNECT,
- SIMPLE_STATE_CONNECT,
- SIMPLE_STATE_DONE
-} SimpleState;
-
-static const char *
-simple_get_string_property (MMCallbackInfo *info, const char *name, GError **error)
-{
- GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties");
- GValue *value;
-
- value = (GValue *) g_hash_table_lookup (properties, name);
- if (!value)
- return NULL;
-
- if (G_VALUE_HOLDS_STRING (value))
- return g_value_get_string (value);
-
- g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Invalid property type for '%s': %s (string expected)",
- name, G_VALUE_TYPE_NAME (value));
-
- return NULL;
-}
-
-static gboolean
-simple_get_uint_property (MMCallbackInfo *info,
- const char *name,
- guint32 *out_val,
- GError **error)
-{
- GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties");
- GValue *value;
-
- g_return_val_if_fail (out_val != NULL, FALSE);
-
- value = (GValue *) g_hash_table_lookup (properties, name);
- if (value) {
- if (G_VALUE_HOLDS_UINT (value)) {
- *out_val = g_value_get_uint (value);
- return TRUE;
- }
-
- g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Invalid property type for '%s': %s (uint expected)",
- name, G_VALUE_TYPE_NAME (value));
- }
-
- return FALSE;
-}
-
-static gboolean
-simple_reg_retry (gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (info->modem),
- simple_reg_callback,
- info);
- return TRUE;
-}
-
-static void
-simple_reg_callback (MMModemCdma *modem,
- MMModemCdmaRegistrationState cdma_1x_reg_state,
- MMModemCdmaRegistrationState evdo_reg_state,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
- gboolean no_service_error = FALSE;
-
- if ( error
- && (error->domain == MM_MOBILE_ERROR)
- && (error->code == MM_MOBILE_ERROR_NO_NETWORK))
- no_service_error = TRUE;
-
- /* Fail immediately on anything but "no service" */
- if (error && !no_service_error) {
- simple_state_machine (MM_MODEM (modem), error, info);
- g_error_free (error);
- return;
- }
-
- if ( no_service_error
- || ( (cdma_1x_reg_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
- && (evdo_reg_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN))) {
- /* Not registered yet, queue up a retry */
- priv->reg_tries++;
- if (priv->reg_tries > 15) {
- error = g_error_new_literal (MM_MOBILE_ERROR,
- MM_MOBILE_ERROR_NO_NETWORK,
- "No service");
- simple_state_machine (MM_MODEM (modem), error, info);
- g_error_free (error);
- return;
- }
-
- /* otherwise, just try again in a bit */
- if (!priv->reg_retry_id)
- priv->reg_retry_id = g_timeout_add_seconds (4, simple_reg_retry, info);
- } else {
- /* Yay, at least one of 1x or EVDO is registered, we can proceed to dial */
- simple_state_machine (MM_MODEM (modem), NULL, info);
- }
-}
-
-static void
-reg_state_changed (MMModemCdma *self,
- MMModemCdmaRegistrationState cdma_1x_new_state,
- MMModemCdmaRegistrationState evdo_new_state,
- gpointer user_data)
-{
-/* Disabled for now... changing the registration state from the
- * subclass' query_registration_state handler also emits the registration
- * state changed signal, which will call this function, and execute
- * simple_state_machine() to advance to the next state. Then however
- * query_registration_state will call its callback, which ends up in
- * simple_reg_callback(), which calls simple_state_machine() too in
- * the same mainloop iteration. Not good. So until that's sorted out
- * we'll just have to poll registration state (every 4 seconds so its
- * not that bad.
- */
-#if 0
- MMCallbackInfo *info = user_data;
-
- /* If we're registered, we can proceed */
- if ( (cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
- || (evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN))
- simple_state_machine (MM_MODEM (modem), NULL, info);
-#endif
-}
-
-static SimpleState
-set_simple_state (MMCallbackInfo *info, SimpleState state)
-{
- mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL);
- return state;
-}
-
-static void
-simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericCdma *self;
- MMGenericCdmaPrivate *priv;
- SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state"));
- const char *str;
- guint id, rm_protocol = 0;
-
- /* Do nothing if modem removed */
- if (!modem || mm_callback_info_check_modem_removed (info))
- return;
-
- if (error) {
- info->error = g_error_copy (error);
- goto out;
- }
-
- self = MM_GENERIC_CDMA (info->modem);
- priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- switch (state) {
- case SIMPLE_STATE_BEGIN:
- /* Enable state */
- state = set_simple_state (info, SIMPLE_STATE_ENABLE);
- mm_modem_enable (modem, simple_state_machine, info);
- break;
- case SIMPLE_STATE_ENABLE:
- /* Register state */
- state = set_simple_state (info, SIMPLE_STATE_REGISTER);
- mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (modem),
- simple_reg_callback,
- info);
- id = g_signal_connect (modem,
- MM_MODEM_CDMA_REGISTRATION_STATE_CHANGED,
- G_CALLBACK (reg_state_changed),
- info);
- priv->reg_state_changed_id = id;
- break;
- case SIMPLE_STATE_REGISTER:
- /* Pre Connect state */
- registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0);
- state = set_simple_state (info, SIMPLE_STATE_PRE_CONNECT);
- mm_modem_set_state (modem, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_REASON_NONE);
-
- /* Change the Rm interface protocol due to manager request if needed */
- if (simple_get_uint_property (info, "rm-protocol", &rm_protocol, &info->error)) {
- mm_generic_cdma_set_rm_protocol (self, rm_protocol, simple_state_machine, info);
- break;
- }
-
- /* Or if the Rm protocol isn't the default, and there was no request
- * to change it, do that now.
- */
- if (priv->cur_crm != priv->orig_crm) {
- mm_generic_cdma_set_rm_protocol (self, priv->orig_crm, simple_state_machine, info);
- break;
- }
-
- /* Fall through */
- case SIMPLE_STATE_PRE_CONNECT:
- /* Connect state */
- state = set_simple_state (info, SIMPLE_STATE_CONNECT);
- str = simple_get_string_property (info, "number", &info->error);
- mm_modem_connect (modem, str, simple_state_machine, info);
- break;
- case SIMPLE_STATE_CONNECT:
- /* All done! */
- state = set_simple_state (info, SIMPLE_STATE_DONE);
- break;
- case SIMPLE_STATE_DONE:
- break;
- }
-
- out:
- if (info->error || state == SIMPLE_STATE_DONE) {
- if (modem)
- registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0);
- mm_callback_info_schedule (info);
- }
-}
-
-static void
-simple_connect (MMModemSimple *simple,
- GHashTable *properties,
- MMModemFn callback,
- gpointer user_data)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (simple);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- MMCallbackInfo *info;
- GError *error = NULL;
-
- if (priv->simple_connect_info) {
- error = g_error_new_literal (MM_MODEM_ERROR,
- MM_MODEM_ERROR_OPERATION_IN_PROGRESS,
- "Connection is already in progress");
- callback (MM_MODEM (simple), error, user_data);
- g_clear_error (&error);
- return;
- }
-
- info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
- priv->simple_connect_info = info;
- mm_callback_info_set_data (info, "simple-connect-properties",
- g_hash_table_ref (properties),
- (GDestroyNotify) g_hash_table_unref);
-
- /* At least number must be present */
- if (!simple_get_string_property (info, "number", &error)) {
- if (!error)
- error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing number property");
- }
-
- simple_state_machine (MM_MODEM (simple), error, info);
- g_clear_error (&error);
-}
-
-static void
-simple_free_gvalue (gpointer data)
-{
- g_value_unset ((GValue *) data);
- g_slice_free (GValue, data);
-}
-
-static GValue *
-simple_uint_value (guint32 i)
-{
- GValue *val;
-
- val = g_slice_new0 (GValue);
- g_value_init (val, G_TYPE_UINT);
- g_value_set_uint (val, i);
-
- return val;
-}
-
-#define SS_HASH_TAG "simple-get-status"
-
-static void
-simple_status_got_signal_quality (MMModem *modem,
- guint32 result,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- GHashTable *properties;
-
- if (error) {
- info->error = g_error_copy (error);
- g_warning ("Error getting signal quality: %s", error->message);
- } else {
- properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG);
- g_hash_table_insert (properties, "signal_quality", simple_uint_value (result));
- }
-
- mm_callback_info_schedule (info);
-}
-
-static void
-simple_get_status_invoke (MMCallbackInfo *info)
-{
- MMModemSimpleGetStatusFn callback = (MMModemSimpleGetStatusFn) info->callback;
-
- callback (MM_MODEM_SIMPLE (info->modem),
- (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG),
- info->error, info->user_data);
-}
-
-static void
-simple_get_status (MMModemSimple *simple,
- MMModemSimpleGetStatusFn callback,
- gpointer user_data)
-{
- GHashTable *properties;
- MMCallbackInfo *info;
-
- info = mm_callback_info_new_full (MM_MODEM (simple),
- simple_get_status_invoke,
- G_CALLBACK (callback),
- user_data);
-
- properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, simple_free_gvalue);
- mm_callback_info_set_data (info, SS_HASH_TAG, properties, (GDestroyNotify) g_hash_table_unref);
- mm_modem_cdma_get_signal_quality (MM_MODEM_CDMA (simple), simple_status_got_signal_quality, info);
-}
-
-/*****************************************************************************/
-
-static void
-modem_valid_changed (MMGenericCdma *self, GParamSpec *pspec, gpointer user_data)
-{
- /* Be paranoid about tearing down any pending registration */
- if (!mm_modem_get_valid (MM_MODEM (self)))
- registration_cleanup (self, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
-}
-
-static void
-modem_state_changed (MMGenericCdma *self, GParamSpec *pspec, gpointer user_data)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
- MMModemState state;
-
- /* Start polling registration status and signal quality when enabled */
-
- state = mm_modem_get_state (MM_MODEM (self));
- if (state >= MM_MODEM_STATE_ENABLED) {
- if (!priv->poll_id) {
- priv->poll_id = g_timeout_add_seconds (30, periodic_poll_cb, self);
- /* Kick one off immediately */
- periodic_poll_cb (self);
- }
- } else {
- if (priv->poll_id)
- g_source_remove (priv->poll_id);
- priv->poll_id = 0;
- }
-}
-
-/*****************************************************************************/
-
-static void
-modem_init (MMModem *modem_class)
-{
- modem_class->owns_port = owns_port;
- modem_class->organize_ports = organize_ports;
- modem_class->release_port = release_port;
- modem_class->enable = enable;
- modem_class->disable = disable;
- modem_class->connect = connect;
- modem_class->disconnect = disconnect;
- modem_class->get_info = get_card_info;
-}
-
-static void
-modem_cdma_init (MMModemCdma *cdma_class)
-{
- cdma_class->get_signal_quality = get_signal_quality;
- cdma_class->get_esn = get_esn;
- cdma_class->get_serving_system = get_serving_system;
- cdma_class->get_registration_state = get_registration_state;
-}
-
-static void
-modem_simple_init (MMModemSimple *class)
-{
- class->connect = simple_connect;
- class->get_status = simple_get_status;
-}
-
-static void
-mm_generic_cdma_init (MMGenericCdma *self)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- g_signal_connect (self, "notify::" MM_MODEM_VALID,
- G_CALLBACK (modem_valid_changed), NULL);
- g_signal_connect (self, "notify::" MM_MODEM_STATE,
- G_CALLBACK (modem_state_changed), NULL);
-
- /* Default to Network Layer Rm interface/PPP */
- priv->orig_crm = priv->cur_crm = RM_PROTO_NETWORK_PPP;
-}
-
-static void
-set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
-
- switch (prop_id) {
- case MM_MODEM_PROP_TYPE:
- break;
- case PROP_EVDO_REV0:
- priv->evdo_rev0 = g_value_get_boolean (value);
- break;
- case PROP_EVDO_REVA:
- priv->evdo_revA = g_value_get_boolean (value);
- break;
- case PROP_REG_TRY_CSS:
- priv->reg_try_css = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
-{
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
-
- switch (prop_id) {
- case MM_MODEM_PROP_DATA_DEVICE:
- if (priv->data)
- g_value_set_string (value, mm_port_get_device (priv->data));
- else
- g_value_set_string (value, NULL);
- break;
- case MM_MODEM_PROP_TYPE:
- g_value_set_uint (value, MM_MODEM_TYPE_CDMA);
- break;
- case MM_MODEM_CDMA_PROP_MEID:
- g_value_set_string (value, priv->meid);
- break;
- case PROP_EVDO_REV0:
- g_value_set_boolean (value, priv->evdo_rev0);
- break;
- case PROP_EVDO_REVA:
- g_value_set_boolean (value, priv->evdo_revA);
- break;
- case PROP_REG_TRY_CSS:
- g_value_set_boolean (value, priv->reg_try_css);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-dispose (GObject *object)
-{
- MMGenericCdma *self = MM_GENERIC_CDMA (object);
- MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
-
- registration_cleanup (self, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
-
- if (priv->poll_id)
- g_source_remove (priv->poll_id);
-
- G_OBJECT_CLASS (mm_generic_cdma_parent_class)->dispose (object);
-}
-
-static void
-mm_generic_cdma_class_init (MMGenericCdmaClass *generic_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (generic_class);
- MMModemBaseClass *base_class = MM_MODEM_BASE_CLASS (generic_class);
-
- mm_generic_cdma_parent_class = g_type_class_peek_parent (generic_class);
- g_type_class_add_private (object_class, sizeof (MMGenericCdmaPrivate));
-
- /* Virtual methods */
- object_class->set_property = set_property;
- object_class->get_property = get_property;
- object_class->dispose = dispose;
- base_class->port_grabbed = port_grabbed;
- generic_class->query_registration_state = real_query_registration_state;
-
- /* Properties */
- g_object_class_override_property (object_class,
- MM_MODEM_PROP_DATA_DEVICE,
- MM_MODEM_DATA_DEVICE);
-
- g_object_class_override_property (object_class,
- MM_MODEM_PROP_TYPE,
- MM_MODEM_TYPE);
-
- g_object_class_override_property (object_class,
- MM_MODEM_CDMA_PROP_MEID,
- MM_MODEM_CDMA_MEID);
-
- g_object_class_install_property (object_class, PROP_EVDO_REV0,
- g_param_spec_boolean (MM_GENERIC_CDMA_EVDO_REV0,
- "EVDO rev0",
- "Supports EVDO rev0",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (object_class, PROP_EVDO_REVA,
- g_param_spec_boolean (MM_GENERIC_CDMA_EVDO_REVA,
- "EVDO revA",
- "Supports EVDO revA",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (object_class, PROP_REG_TRY_CSS,
- g_param_spec_boolean (MM_GENERIC_CDMA_REGISTRATION_TRY_CSS,
- "RegistrationTryCss",
- "Use Serving System response when checking modem"
- " registration state.",
- TRUE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-}
-