base-modem: ported all port grabbing/releasing logic to the base object

This commit is contained in:
Aleksander Morgado
2011-11-04 12:43:06 +01:00
parent f39923c97d
commit b6cb5bd6da
2 changed files with 230 additions and 100 deletions

View File

@@ -52,6 +52,10 @@ struct _MMBaseModemPrivate {
MMAuthProvider *authp;
GHashTable *ports;
MMAtSerialPort *primary;
MMAtSerialPort *secondary;
MMQcdmSerialPort *qcdm;
MMPort *data;
};
static gchar *
@@ -85,6 +89,14 @@ mm_base_modem_get_port (MMBaseModem *self,
return port;
}
gboolean
mm_base_modem_owns_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name)
{
return !!mm_base_modem_get_port (self, subsys, name);
}
static gboolean
set_invalid_unresponsive_modem_cb (MMBaseModem *self)
{
@@ -102,11 +114,11 @@ serial_port_timed_out_cb (MMSerialPort *port,
if (self->priv->max_timeouts > 0 &&
n_consecutive_timeouts >= self->priv->max_timeouts) {
mm_warn ("Modem %s: Port (%s/%s) timed out %u times, marking modem as disabled",
g_dbus_object_get_object_path (G_DBUS_OBJECT (self)),
mm_warn ("(%s/%s) port timed out %u times, marking modem '%s' as disabled",
mm_port_type_to_name (mm_port_get_port_type (MM_PORT (port))),
mm_port_get_device (MM_PORT (port)),
n_consecutive_timeouts);
n_consecutive_timeouts,
g_dbus_object_get_object_path (G_DBUS_OBJECT (self)));
/* Only set action to invalidate modem if not already done */
if (!self->priv->set_invalid_unresponsive_modem_id)
@@ -115,118 +127,236 @@ serial_port_timed_out_cb (MMSerialPort *port,
}
}
static void
find_primary (gpointer key, gpointer data, gpointer user_data)
gboolean
mm_base_modem_grab_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name,
MMPortType suggested_type)
{
MMPort **found = user_data;
MMPort *port = MM_PORT (data);
MMPort *port;
gchar *key;
if (!*found && (mm_port_get_port_type (port) == MM_PORT_TYPE_PRIMARY))
*found = port;
}
g_return_val_if_fail (MM_IS_BASE_MODEM (self), FALSE);
g_return_val_if_fail (subsys != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
MMPort *
mm_base_modem_add_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name,
MMPortType ptype)
{
MMPort *port = NULL;
gchar *key, *device;
/* Only allow 'tty' and 'net' ports */
if (!g_str_equal (subsys, "net") &&
!g_str_equal (subsys, "tty")) {
mm_warn ("(%s/%s): cannot add port, unhandled subsystem",
subsys, name);
return FALSE;
}
g_return_val_if_fail (MM_IS_BASE_MODEM (self), NULL);
g_return_val_if_fail (subsys != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (ptype != MM_PORT_TYPE_UNKNOWN, NULL);
/* Only 'net' or 'tty' should be given */
g_return_val_if_fail (g_str_equal (subsys, "net") ||
g_str_equal (subsys, "tty"),
NULL);
/* Don't allow more than one Primary port to be set */
if (self->priv->primary &&
suggested_type == MM_PORT_TYPE_PRIMARY) {
mm_warn ("(%s/%s): cannot add port, primary port already exists",
subsys, name);
return FALSE;
}
/* Check whether we already have it stored */
key = get_hash_key (subsys, name);
port = g_hash_table_lookup (self->priv->ports, key);
if (port) {
mm_warn ("cannot add port (%s/%s): already exists",
mm_warn ("(%s/%s): cannot add port, already exists",
subsys, name);
g_free (key);
return NULL;
}
if (ptype == MM_PORT_TYPE_PRIMARY) {
g_hash_table_foreach (self->priv->ports, find_primary, &port);
if (port) {
mm_warn ("cannot add port (%s/%s): primary port already exists",
subsys, name);
g_free (key);
return NULL;
}
return FALSE;
}
/* If we have a tty, decide whether it will be primary, secondary, or none */
if (g_str_equal (subsys, "tty")) {
if (ptype == MM_PORT_TYPE_QCDM)
MMPortType ptype;
/* Decide port type */
if (suggested_type != MM_PORT_TYPE_UNKNOWN)
ptype = suggested_type;
else {
if (!self->priv->primary)
ptype = MM_PORT_TYPE_PRIMARY;
else if (!self->priv->secondary)
ptype = MM_PORT_TYPE_SECONDARY;
else
ptype = MM_PORT_TYPE_IGNORED;
}
if (ptype == MM_PORT_TYPE_QCDM) {
/* QCDM port */
port = MM_PORT (mm_qcdm_serial_port_new (name, ptype));
else
if (!self->priv->qcdm)
self->priv->qcdm = g_object_ref (port);
} else {
/* AT port */
port = MM_PORT (mm_at_serial_port_new (name, ptype));
/* TODO: setup serial port response parser and unsolicited message handlers */
/* (CDMA) */
/* g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL); */
/* 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); */
/* (GSM) */
/* { */
/* GPtrArray *array; */
/* int i; */
/* mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port), */
/* mm_serial_parser_v1_parse, */
/* mm_serial_parser_v1_new (), */
/* mm_serial_parser_v1_destroy); */
/* /\* Set up CREG unsolicited message handlers *\/ */
/* array = mm_gsm_creg_regex_get (FALSE); */
/* for (i = 0; i < array->len; i++) { */
/* regex = g_ptr_array_index (array, i); */
/* mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, reg_state_changed, self, NULL); */
/* } */
/* mm_gsm_creg_regex_destroy (array); */
/* regex = g_regex_new ("\\r\\n\\+CIEV: (\\d+),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); */
/* mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, ciev_received, self, NULL); */
/* g_regex_unref (regex); */
/* regex = g_regex_new ("\\r\\n\\+CMTI: \"(\\S+)\",(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); */
/* mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, cmti_received, self, NULL); */
/* g_regex_unref (regex); */
/* regex = g_regex_new ("\\r\\n\\+CUSD:\\s*(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); */
/* mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, cusd_received, self, NULL); */
/* g_regex_unref (regex); */
/* } */
if (ptype == MM_PORT_TYPE_PRIMARY) {
self->priv->primary = g_object_ref (port);
/* Primary port, which will also be data port */
if (!self->priv->data)
self->priv->data = g_object_ref (port);
/* TODO: GSM */
/* /\* Get the modem's general info *\/ */
/* initial_info_check (self); */
/* /\* Get modem's IMEI *\/ */
/* initial_imei_check (self); */
/* /\* Get modem's initial lock/unlock state; this also ensures the */
/* * SIM is ready by waiting if necessary for the SIM to initalize. */
/* *\/ */
/* initial_pin_check (self); */
/* TODO: CDMA */
/* /\* Get the modem's general info *\/ */
/* initial_info_check (self); */
/* /\* Get modem's ESN number *\/ */
/* initial_esn_check (self); */
} else if (ptype == MM_PORT_TYPE_SECONDARY)
self->priv->secondary = g_object_ref (port);
}
/* For serial ports, enable port timeout checks */
if (port)
g_signal_connect (port,
"timed-out",
G_CALLBACK (serial_port_timed_out_cb),
self);
} else if (!strcmp (subsys, "net")) {
mm_dbg ("(%s/%s) port (%s) grabbed by %s",
subsys,
name,
mm_port_type_to_name (ptype),
mm_port_get_device (port));
} else {
/* Net */
port = MM_PORT (g_object_new (MM_TYPE_PORT,
MM_PORT_DEVICE, name,
MM_PORT_SUBSYS, MM_PORT_SUBSYS_NET,
MM_PORT_TYPE, ptype,
MM_PORT_TYPE, MM_PORT_TYPE_IGNORED,
NULL));
}
device = mm_modem_get_device (MM_MODEM (self));
mm_dbg ("(%s/%s) type %s claimed by %s",
subsys,
name,
mm_port_type_to_name (ptype),
device);
g_free (device);
/* Net device (if any) is the preferred data port */
if (!self->priv->data || MM_IS_AT_SERIAL_PORT (self->priv->data)) {
g_clear_object (&self->priv->data);
self->priv->data = g_object_ref (port);
g_hash_table_insert (self->priv->ports, key, port);
/* TODO: */
/* g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE); */
/* check_valid (self); */
}
return port;
}
gboolean
mm_base_modem_remove_port (MMBaseModem *self, MMPort *port)
{
gchar *device, *key, *name;
const gchar *type_name, *subsys;
gboolean removed;
g_return_val_if_fail (MM_IS_BASE_MODEM (self), FALSE);
g_return_val_if_fail (MM_IS_PORT (port), FALSE);
name = g_strdup (mm_port_get_device (port));
subsys = mm_port_subsys_to_name (mm_port_get_subsys (port));
type_name = mm_port_type_to_name (mm_port_get_port_type (port));
key = get_hash_key (subsys, name);
removed = g_hash_table_remove (self->priv->ports, key);
if (removed) {
/* Port may have already been destroyed by removal from the hash */
device = mm_modem_get_device (MM_MODEM (self));
mm_dbg ("(%s/%s) type %s removed from %s",
mm_dbg ("(%s/%s) port grabbed by %s",
subsys,
name,
type_name,
device);
g_free (device);
mm_port_get_device (port));
}
g_free (key);
g_free (name);
return removed;
/* Add it to the tracking HT.
* Note: 'key' and 'port' now owned by the HT. */
g_hash_table_insert (self->priv->ports, key, port);
return TRUE;
}
void
mm_base_modem_release_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name)
{
const gchar *type_name;
const gchar *device;
gchar *key;
MMPort *port;
g_return_if_fail (MM_IS_BASE_MODEM (self));
g_return_if_fail (name != NULL);
g_return_if_fail (subsys != NULL);
if (!g_str_equal (subsys, "tty") &&
!g_str_equal (subsys, "net"))
return;
key = get_hash_key (subsys, name);
/* Find the port */
port = g_hash_table_lookup (self->priv->ports, key);
if (!port) {
mm_warn ("(%s/%s): cannot release port, not found",
subsys, name);
g_free (key);
return;
}
if (port == (MMPort *)self->priv->primary)
g_clear_object (&self->priv->primary);
if (port == (MMPort *)self->priv->data)
g_clear_object (&self->priv->data);
if (port == (MMPort *)self->priv->secondary)
g_clear_object (&self->priv->secondary);
if (port == (MMPort *)self->priv->qcdm)
g_clear_object (&self->priv->qcdm);
/* Remove it from the tracking HT */
type_name = mm_port_type_to_name (mm_port_get_port_type (port));
device = mm_port_get_device (port);
mm_dbg ("(%s/%s) type %s released from %s",
subsys,
name,
type_name,
device);
g_hash_table_remove (self->priv->ports, key);
g_free (key);
/* TODO */
/* check_valid (MM_GENERIC_GSM (modem)); */
}
void
@@ -237,15 +367,6 @@ mm_base_modem_set_valid (MMBaseModem *self,
if (self->priv->valid != new_valid) {
self->priv->valid = new_valid;
/* TODO */
/* /\* Modem starts off in disabled state, and jumps to disabled when */
/* * it's no longer valid. */
/* *\/ */
/* mm_modem_set_state (MM_MODEM (self), */
/* MM_MODEM_STATE_DISABLED, */
/* MM_MODEM_STATE_REASON_NONE); */
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALID]);
}
}
@@ -371,6 +492,11 @@ dispose (GObject *object)
{
MMBaseModem *self = MM_BASE_MODEM (object);
g_clear_object (&self->priv->primary);
g_clear_object (&self->priv->secondary);
g_clear_object (&self->priv->data);
g_clear_object (&self->priv->qcdm);
if (self->priv->ports) {
g_hash_table_destroy (self->priv->ports);
self->priv->ports = NULL;