Files
ModemManager/plugins/option/mm-broadband-modem-hso.c
T
Aleksander Morgado d818d9fe06 bearer: consolidate unsolicited connection status reports
Originally developed by:
  Ben Chan <benchan@chromium.org>

This patch replaces mm_bearer_report_disconnection() with a more generic
mm_bearer_report_connection_status(), which allows reporting any
connection status of a bearer. This further allows getting rid of those
custom report_connection_status functions in plugic specific bearer
subclasses.

Note that while plugin-specific implementations can receive multiple
'MMBearerConnectionStatus' values, the generic implementation is only allowed
to receive DISCONNECTED. Plugins need to make sure that they process all the
other status values, and only report DISCONNECTED to the parent when required.

MBM:
  The MBM bearer implementation of report_connection_status() expects either
  CONNECTED or DISCONNECTED. If any of these is received and there is an ongoing
  connection attempt, the corresponding operation will be completed. If there is
  no connection attempt, we will just handle the DISCONNECTED state, calling the
  parent method to notify that the modem got network-disconnected.

Icera:
  The Icera bearer implementation of report_connection_status() expects either
  CONNECTED, CONNECT FAILED or DISCONNECTED. If any of these is received and
  there is an ongoing connection or disconnection attempt, the corresponding
  operation will be completed. If there is no connection or disconnection
  attempt, we will just handle the CONNECT FAILED and DISCONNECTED states,
  calling the parent method (always with DISCONNECTED) to notify that the modem
  got network-disconnected.

Option/HSO:
  The Option/HSO bearer implementation of report_connection_status() expects
  either CONNECTED, CONNECTION FAILED or DISCONNECTED. If any of these is
  received and there is an ongoing connection or disconnection attempt, the
  corresponding operation will be completed. If there is no connection or
  disconnection attempt, we will just handle the CONNECTION FAILED and
  DISCONNECTED states, calling the parent method (always with DISCONNECTED) to
  notify that the modem got network-disconnected.

Huawei:
  The Huawei bearer implementation of report_connection_status() expects either
  CONNECTED or DISCONNECTED. These messages are not used to process pending
  connection or disconnection attempts; so if they are received while one of
  these is on-going, it will just be ignored. CONNECTED reports are also
  ignored, so we will just handle the DISCONNECTED state, calling the parent
  method to notify that the modem got network-disconnected.

Altair-LTE:
  The Altair-LTE bearers will only report DISCONNECTED on network-disconnected
  cases. There is no custom report_connection_status().

Novatel-LTE:
  The Novatel-LTE bearers will only report DISCONNECTED on network-disconnected
  cases. There is no custom report_connection_status().
2013-09-23 08:29:15 +02:00

815 lines
30 KiB
C

/* -*- 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 hso) 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 - 2012 Red Hat, Inc.
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "ModemManager.h"
#include "mm-modem-helpers.h"
#include "mm-log.h"
#include "mm-errors-types.h"
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
#include "mm-iface-modem-location.h"
#include "mm-base-modem-at.h"
#include "mm-broadband-modem-hso.h"
#include "mm-broadband-bearer-hso.h"
#include "mm-bearer-list.h"
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
static void iface_modem_location_init (MMIfaceModemLocation *iface);
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
static MMIfaceModemLocation *iface_modem_location_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemHso, mm_broadband_modem_hso, MM_TYPE_BROADBAND_MODEM_OPTION, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init));
struct _MMBroadbandModemHsoPrivate {
/* Regex for connected notifications */
GRegex *_owancall_regex;
MMModemLocationSource enabled_sources;
};
/*****************************************************************************/
/* Create Bearer (Modem interface) */
static MMBearer *
modem_create_bearer_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
MMBearer *bearer;
bearer = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
mm_dbg ("New %s bearer created at DBus path '%s'",
MM_IS_BROADBAND_BEARER_HSO (bearer) ? "HSO" : "Generic",
mm_bearer_get_path (bearer));
return g_object_ref (bearer);
}
static void
broadband_bearer_new_ready (GObject *source,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
MMBearer *bearer = NULL;
GError *error = NULL;
bearer = mm_broadband_bearer_new_finish (res, &error);
if (!bearer)
g_simple_async_result_take_error (simple, error);
else
g_simple_async_result_set_op_res_gpointer (simple,
bearer,
(GDestroyNotify)g_object_unref);
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
broadband_bearer_hso_new_ready (GObject *source,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
MMBearer *bearer = NULL;
GError *error = NULL;
bearer = mm_broadband_bearer_hso_new_finish (res, &error);
if (!bearer)
g_simple_async_result_take_error (simple, error);
else
g_simple_async_result_set_op_res_gpointer (simple,
bearer,
(GDestroyNotify)g_object_unref);
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
modem_create_bearer (MMIfaceModem *self,
MMBearerProperties *properties,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
modem_create_bearer);
if (mm_bearer_properties_get_ip_type (properties) &
(MM_BEARER_IP_FAMILY_IPV6 | MM_BEARER_IP_FAMILY_IPV4V6)) {
mm_dbg ("Creating generic bearer (IPv6 requested)...");
mm_broadband_bearer_new (MM_BROADBAND_MODEM (self),
properties,
NULL, /* cancellable */
(GAsyncReadyCallback)broadband_bearer_new_ready,
result);
return;
}
mm_dbg ("Creating HSO bearer...");
mm_broadband_bearer_hso_new (MM_BROADBAND_MODEM_HSO (self),
properties,
NULL, /* cancellable */
(GAsyncReadyCallback)broadband_bearer_hso_new_ready,
result);
}
/*****************************************************************************/
/* Load unlock retries (Modem interface) */
static MMUnlockRetries *
load_unlock_retries_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
return NULL;
return (MMUnlockRetries *) g_object_ref (g_simple_async_result_get_op_res_gpointer (
G_SIMPLE_ASYNC_RESULT (res)));
}
static void
load_unlock_retries_ready (MMBaseModem *self,
GAsyncResult *res,
GSimpleAsyncResult *operation_result)
{
const gchar *response;
GError *error = NULL;
int pin1, puk1;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (!response) {
mm_dbg ("Couldn't query unlock retries: '%s'", error->message);
g_simple_async_result_take_error (operation_result, error);
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
return;
}
response = mm_strip_tag (response, "_OERCN:");
if (sscanf (response, " %d, %d", &pin1, &puk1) == 2) {
MMUnlockRetries *retries;
retries = mm_unlock_retries_new ();
mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, pin1);
mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, puk1);
g_simple_async_result_set_op_res_gpointer (operation_result,
retries,
(GDestroyNotify)g_object_unref);
} else {
g_simple_async_result_set_error (operation_result,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Invalid unlock retries response: '%s'",
response);
}
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
}
static void
load_unlock_retries (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"_OERCN?",
3,
FALSE,
(GAsyncReadyCallback)load_unlock_retries_ready,
g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
load_unlock_retries));
}
/*****************************************************************************/
/* Setup/Cleanup unsolicited events (3GPP interface) */
typedef struct {
guint cid;
MMBearerConnectionStatus status;
} BearerListReportStatusForeachContext;
static void
bearer_list_report_status_foreach (MMBearer *bearer,
BearerListReportStatusForeachContext *ctx)
{
if (mm_broadband_bearer_get_3gpp_cid (MM_BROADBAND_BEARER (bearer)) != ctx->cid)
return;
mm_bearer_report_connection_status (MM_BEARER (bearer), ctx->status);
}
static void
hso_connection_status_changed (MMAtSerialPort *port,
GMatchInfo *match_info,
MMBroadbandModemHso *self)
{
MMBearerList *list = NULL;
BearerListReportStatusForeachContext ctx;
guint cid;
guint status;
/* Ensure we got proper parsed values */
if (!mm_get_uint_from_match_info (match_info, 1, &cid) ||
!mm_get_uint_from_match_info (match_info, 2, &status))
return;
/* Setup context */
ctx.cid = cid;
ctx.status = MM_BEARER_CONNECTION_STATUS_UNKNOWN;
switch (status) {
case 1:
ctx.status = MM_BEARER_CONNECTION_STATUS_CONNECTED;
break;
case 3:
ctx.status = MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED;
break;
case 0:
ctx.status = MM_BEARER_CONNECTION_STATUS_DISCONNECTED;
break;
default:
break;
}
/* If unknown status, don't try to report anything */
if (ctx.status == MM_BEARER_CONNECTION_STATUS_UNKNOWN)
return;
/* If empty bearer list, nothing else to do */
g_object_get (self,
MM_IFACE_MODEM_BEARER_LIST, &list,
NULL);
if (!list)
return;
/* Will report status only in the bearer with the specific CID */
mm_bearer_list_foreach (list,
(MMBearerListForeachFunc)bearer_list_report_status_foreach,
&ctx);
g_object_unref (list);
}
static gboolean
modem_3gpp_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void
parent_setup_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
GError *error = NULL;
if (!iface_modem_3gpp_parent->setup_unsolicited_events_finish (self, res, &error))
g_simple_async_result_take_error (simple, error);
else {
/* Our own setup now */
mm_at_serial_port_add_unsolicited_msg_handler (
mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
MM_BROADBAND_MODEM_HSO (self)->priv->_owancall_regex,
(MMAtSerialUnsolicitedMsgFn)hso_connection_status_changed,
self,
NULL);
g_simple_async_result_set_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res), TRUE);
}
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
modem_3gpp_setup_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
modem_3gpp_setup_unsolicited_events);
/* Chain up parent's setup */
iface_modem_3gpp_parent->setup_unsolicited_events (
self,
(GAsyncReadyCallback)parent_setup_unsolicited_events_ready,
result);
}
static void
parent_cleanup_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
GError *error = NULL;
if (!iface_modem_3gpp_parent->cleanup_unsolicited_events_finish (self, res, &error))
g_simple_async_result_take_error (simple, error);
else
g_simple_async_result_set_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res), TRUE);
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
modem_3gpp_cleanup_unsolicited_events);
/* Our own cleanup first */
mm_at_serial_port_add_unsolicited_msg_handler (
mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
MM_BROADBAND_MODEM_HSO (self)->priv->_owancall_regex,
NULL, NULL, NULL);
/* And now chain up parent's cleanup */
iface_modem_3gpp_parent->cleanup_unsolicited_events (
self,
(GAsyncReadyCallback)parent_cleanup_unsolicited_events_ready,
result);
}
/*****************************************************************************/
/* Location capabilities loading (Location interface) */
static MMModemLocationSource
location_load_capabilities_finish (MMIfaceModemLocation *self,
GAsyncResult *res,
GError **error)
{
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
return MM_MODEM_LOCATION_SOURCE_NONE;
return (MMModemLocationSource) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
G_SIMPLE_ASYNC_RESULT (res)));
}
static void
parent_load_capabilities_ready (MMIfaceModemLocation *self,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
MMModemLocationSource sources;
GError *error = NULL;
sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
if (error) {
g_simple_async_result_take_error (simple, error);
g_simple_async_result_complete (simple);
g_object_unref (simple);
return;
}
/* Now our own check.
*
* We could issue AT_OIFACE? to list the interfaces currently enabled in the
* module, to see if there is a 'GPS' interface enabled. But we'll just go
* and see if there is already a 'GPS control' AT port and a raw serial 'GPS'
* port grabbed.
*
* NOTE: A deeper implementation could handle the situation where the GPS
* interface is found disabled in AT_OIFACE?. In this case, we could issue
* AT_OIFACE="GPS",1 to enable it (and AT_OIFACE="GPS",0 to disable it), but
* enabling/disabling GPS involves a complete reboot of the modem, which is
* probably not the desired thing here.
*/
if (mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)) &&
mm_base_modem_peek_port_gps_control (MM_BASE_MODEM (self)))
sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW);
/* So we're done, complete */
g_simple_async_result_set_op_res_gpointer (simple,
GUINT_TO_POINTER (sources),
NULL);
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
location_load_capabilities (MMIfaceModemLocation *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
location_load_capabilities);
/* Chain up parent's setup */
iface_modem_location_parent->load_capabilities (
self,
(GAsyncReadyCallback)parent_load_capabilities_ready,
result);
}
/*****************************************************************************/
/* Disable location gathering (Location interface) */
static gboolean
disable_location_gathering_finish (MMIfaceModemLocation *self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void
gps_disabled_ready (MMBaseModem *self,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
MMGpsSerialPort *gps_port;
GError *error = NULL;
if (!mm_base_modem_at_command_full_finish (self, res, &error))
g_simple_async_result_take_error (simple, error);
else
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
/* Even if we get an error here, we try to close the GPS port */
gps_port = mm_base_modem_peek_port_gps (self);
if (gps_port)
mm_serial_port_close (MM_SERIAL_PORT (gps_port));
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
disable_location_gathering (MMIfaceModemLocation *self,
MMModemLocationSource source,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemHso *hso = MM_BROADBAND_MODEM_HSO (self);
GSimpleAsyncResult *result;
gboolean stop_gps = FALSE;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
disable_location_gathering);
/* Only stop GPS engine if no GPS-related sources enabled */
if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
hso->priv->enabled_sources &= ~source;
if (!(hso->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
stop_gps = TRUE;
}
if (stop_gps) {
/* We enable continuous GPS fixes with AT_OGPS=0 */
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
mm_base_modem_peek_port_gps_control (MM_BASE_MODEM (self)),
"_OGPS=0",
3,
FALSE,
FALSE, /* raw */
NULL, /* cancellable */
(GAsyncReadyCallback)gps_disabled_ready,
result);
return;
}
/* For any other location (e.g. 3GPP), or if still some GPS needed, just return */
g_simple_async_result_set_op_res_gboolean (result, TRUE);
g_simple_async_result_complete_in_idle (result);
g_object_unref (result);
}
/*****************************************************************************/
/* Enable location gathering (Location interface) */
typedef struct {
MMBroadbandModemHso *self;
GSimpleAsyncResult *result;
MMModemLocationSource source;
} EnableLocationGatheringContext;
static void
enable_location_gathering_context_complete_and_free (EnableLocationGatheringContext *ctx)
{
g_simple_async_result_complete (ctx->result);
g_object_unref (ctx->result);
g_object_unref (ctx->self);
g_free (ctx);
}
static gboolean
enable_location_gathering_finish (MMIfaceModemLocation *self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void
gps_enabled_ready (MMBaseModem *self,
GAsyncResult *res,
EnableLocationGatheringContext *ctx)
{
MMGpsSerialPort *gps_port;
GError *error = NULL;
if (!mm_base_modem_at_command_full_finish (self, res, &error)) {
g_simple_async_result_take_error (ctx->result, error);
enable_location_gathering_context_complete_and_free (ctx);
return;
}
gps_port = mm_base_modem_peek_port_gps (self);
if (!gps_port ||
!mm_serial_port_open (MM_SERIAL_PORT (gps_port), &error)) {
if (error)
g_simple_async_result_take_error (ctx->result, error);
else
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Couldn't open raw GPS serial port");
} else
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
enable_location_gathering_context_complete_and_free (ctx);
}
static void
parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
GAsyncResult *res,
EnableLocationGatheringContext *ctx)
{
gboolean start_gps = FALSE;
GError *error = NULL;
if (!iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) {
g_simple_async_result_take_error (ctx->result, error);
enable_location_gathering_context_complete_and_free (ctx);
return;
}
/* Now our own enabling */
/* NMEA and RAW are both enabled in the same way */
if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
/* Only start GPS engine if not done already */
if (!(ctx->self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
start_gps = TRUE;
ctx->self->priv->enabled_sources |= ctx->source;
}
if (start_gps) {
/* We enable continuous GPS fixes with AT_OGPS=2 */
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
mm_base_modem_peek_port_gps_control (MM_BASE_MODEM (self)),
"_OGPS=2",
3,
FALSE,
FALSE, /* raw */
NULL, /* cancellable */
(GAsyncReadyCallback)gps_enabled_ready,
ctx);
return;
}
/* For any other location (e.g. 3GPP), or if GPS already running just return */
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
enable_location_gathering_context_complete_and_free (ctx);
}
static void
enable_location_gathering (MMIfaceModemLocation *self,
MMModemLocationSource source,
GAsyncReadyCallback callback,
gpointer user_data)
{
EnableLocationGatheringContext *ctx;
ctx = g_new (EnableLocationGatheringContext, 1);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
enable_location_gathering);
ctx->source = source;
/* Chain up parent's gathering enable */
iface_modem_location_parent->enable_location_gathering (
self,
source,
(GAsyncReadyCallback)parent_enable_location_gathering_ready,
ctx);
}
/*****************************************************************************/
/* Setup ports (Broadband modem class) */
static void
trace_received (MMGpsSerialPort *port,
const gchar *trace,
MMIfaceModemLocation *self)
{
/* Helper to debug GPS location related issues. Don't depend on a real GPS
* fix for debugging, just use some random values to update */
#if 0
if (g_str_has_prefix (trace, "$GPGGA")) {
GString *str;
GDateTime *now;
now = g_date_time_new_now_utc ();
str = g_string_new ("");
g_string_append_printf (str,
"$GPGGA,%02u%02u%02u,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47",
g_date_time_get_hour (now),
g_date_time_get_minute (now),
g_date_time_get_second (now));
mm_iface_modem_location_gps_update (self, str->str);
g_string_free (str, TRUE);
g_date_time_unref (now);
return;
}
#endif
mm_iface_modem_location_gps_update (self, trace);
}
static void
setup_ports (MMBroadbandModem *self)
{
MMAtSerialPort *gps_control_port;
MMGpsSerialPort *gps_data_port;
/* Call parent's setup ports first always */
MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_hso_parent_class)->setup_ports (self);
/* _OWANCALL unsolicited messages are only expected in the primary port. */
mm_at_serial_port_add_unsolicited_msg_handler (
mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
MM_BROADBAND_MODEM_HSO (self)->priv->_owancall_regex,
NULL, NULL, NULL);
g_object_set (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
MM_SERIAL_PORT_SEND_DELAY, (guint64) 0,
/* built-in echo removal conflicts with unsolicited _OWANCALL
* messages, which are not <CR><LF> prefixed. */
MM_AT_SERIAL_PORT_REMOVE_ECHO, FALSE,
NULL);
gps_control_port = mm_base_modem_peek_port_gps_control (MM_BASE_MODEM (self));
gps_data_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self));
if (gps_control_port && gps_data_port) {
/* It may happen that the modem was started with GPS already enabled, or
* maybe ModemManager got rebooted and it was left enabled before. We'll make
* sure that it is disabled when we initialize the modem */
mm_base_modem_at_command_full (MM_BASE_MODEM (self),
gps_control_port,
"_OGPS=0",
3, FALSE, FALSE, NULL, NULL, NULL);
/* Add handler for the NMEA traces */
mm_gps_serial_port_add_trace_handler (gps_data_port,
(MMGpsSerialTraceFn)trace_received,
self,
NULL);
}
}
/*****************************************************************************/
MMBroadbandModemHso *
mm_broadband_modem_hso_new (const gchar *device,
const gchar **drivers,
const gchar *plugin,
guint16 vendor_id,
guint16 product_id)
{
return g_object_new (MM_TYPE_BROADBAND_MODEM_HSO,
MM_BASE_MODEM_DEVICE, device,
MM_BASE_MODEM_DRIVERS, drivers,
MM_BASE_MODEM_PLUGIN, plugin,
MM_BASE_MODEM_VENDOR_ID, vendor_id,
MM_BASE_MODEM_PRODUCT_ID, product_id,
NULL);
}
static void
finalize (GObject *object)
{
MMBroadbandModemHso *self = MM_BROADBAND_MODEM_HSO (object);
g_regex_unref (self->priv->_owancall_regex);
G_OBJECT_CLASS (mm_broadband_modem_hso_parent_class)->finalize (object);
}
static void
mm_broadband_modem_hso_init (MMBroadbandModemHso *self)
{
/* Initialize private data */
self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
MM_TYPE_BROADBAND_MODEM_HSO,
MMBroadbandModemHsoPrivate);
self->priv->_owancall_regex = g_regex_new ("_OWANCALL: (\\d),\\s*(\\d)\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
self->priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
}
static void
iface_modem_init (MMIfaceModem *iface)
{
iface->create_bearer = modem_create_bearer;
iface->create_bearer_finish = modem_create_bearer_finish;
iface->load_unlock_retries = load_unlock_retries;
iface->load_unlock_retries_finish = load_unlock_retries_finish;
/* HSO modems don't need the extra 10s wait after powering up */
iface->modem_after_power_up = NULL;
iface->modem_after_power_up_finish = NULL;
}
static void
iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
{
iface_modem_3gpp_parent = g_type_interface_peek_parent (iface);
iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events;
iface->setup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish;
iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events;
iface->cleanup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish;
}
static void
iface_modem_location_init (MMIfaceModemLocation *iface)
{
iface_modem_location_parent = g_type_interface_peek_parent (iface);
iface->load_capabilities = location_load_capabilities;
iface->load_capabilities_finish = location_load_capabilities_finish;
iface->enable_location_gathering = enable_location_gathering;
iface->enable_location_gathering_finish = enable_location_gathering_finish;
iface->disable_location_gathering = disable_location_gathering;
iface->disable_location_gathering_finish = disable_location_gathering_finish;
}
static void
mm_broadband_modem_hso_class_init (MMBroadbandModemHsoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMBroadbandModemHsoPrivate));
object_class->finalize = finalize;
broadband_modem_class->setup_ports = setup_ports;
}