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; MMAuthProvider *authp;
GHashTable *ports; GHashTable *ports;
MMAtSerialPort *primary;
MMAtSerialPort *secondary;
MMQcdmSerialPort *qcdm;
MMPort *data;
}; };
static gchar * static gchar *
@@ -85,6 +89,14 @@ mm_base_modem_get_port (MMBaseModem *self,
return port; 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 static gboolean
set_invalid_unresponsive_modem_cb (MMBaseModem *self) set_invalid_unresponsive_modem_cb (MMBaseModem *self)
{ {
@@ -102,11 +114,11 @@ serial_port_timed_out_cb (MMSerialPort *port,
if (self->priv->max_timeouts > 0 && if (self->priv->max_timeouts > 0 &&
n_consecutive_timeouts >= self->priv->max_timeouts) { n_consecutive_timeouts >= self->priv->max_timeouts) {
mm_warn ("Modem %s: Port (%s/%s) timed out %u times, marking modem as disabled", mm_warn ("(%s/%s) port timed out %u times, marking modem '%s' as disabled",
g_dbus_object_get_object_path (G_DBUS_OBJECT (self)),
mm_port_type_to_name (mm_port_get_port_type (MM_PORT (port))), mm_port_type_to_name (mm_port_get_port_type (MM_PORT (port))),
mm_port_get_device (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 */ /* Only set action to invalidate modem if not already done */
if (!self->priv->set_invalid_unresponsive_modem_id) if (!self->priv->set_invalid_unresponsive_modem_id)
@@ -115,118 +127,236 @@ serial_port_timed_out_cb (MMSerialPort *port,
} }
} }
static void gboolean
find_primary (gpointer key, gpointer data, gpointer user_data) mm_base_modem_grab_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name,
MMPortType suggested_type)
{ {
MMPort **found = user_data; MMPort *port;
MMPort *port = MM_PORT (data); gchar *key;
if (!*found && (mm_port_get_port_type (port) == MM_PORT_TYPE_PRIMARY)) g_return_val_if_fail (MM_IS_BASE_MODEM (self), FALSE);
*found = port; g_return_val_if_fail (subsys != NULL, FALSE);
} g_return_val_if_fail (name != NULL, FALSE);
MMPort * /* Only allow 'tty' and 'net' ports */
mm_base_modem_add_port (MMBaseModem *self, if (!g_str_equal (subsys, "net") &&
const gchar *subsys, !g_str_equal (subsys, "tty")) {
const gchar *name, mm_warn ("(%s/%s): cannot add port, unhandled subsystem",
MMPortType ptype) subsys, name);
{ return FALSE;
MMPort *port = NULL; }
gchar *key, *device;
g_return_val_if_fail (MM_IS_BASE_MODEM (self), NULL); /* Don't allow more than one Primary port to be set */
g_return_val_if_fail (subsys != NULL, NULL); if (self->priv->primary &&
g_return_val_if_fail (name != NULL, NULL); suggested_type == MM_PORT_TYPE_PRIMARY) {
g_return_val_if_fail (ptype != MM_PORT_TYPE_UNKNOWN, NULL); mm_warn ("(%s/%s): cannot add port, primary port already exists",
subsys, name);
/* Only 'net' or 'tty' should be given */ return FALSE;
g_return_val_if_fail (g_str_equal (subsys, "net") || }
g_str_equal (subsys, "tty"),
NULL);
/* Check whether we already have it stored */
key = get_hash_key (subsys, name); key = get_hash_key (subsys, name);
port = g_hash_table_lookup (self->priv->ports, key); port = g_hash_table_lookup (self->priv->ports, key);
if (port) { if (port) {
mm_warn ("cannot add port (%s/%s): already exists", mm_warn ("(%s/%s): cannot add port, already exists",
subsys, name); subsys, name);
g_free (key); g_free (key);
return NULL; return FALSE;
}
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;
}
} }
/* If we have a tty, decide whether it will be primary, secondary, or none */
if (g_str_equal (subsys, "tty")) { 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)); 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)); 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 */ /* For serial ports, enable port timeout checks */
if (port) if (port)
g_signal_connect (port, g_signal_connect (port,
"timed-out", "timed-out",
G_CALLBACK (serial_port_timed_out_cb), G_CALLBACK (serial_port_timed_out_cb),
self); 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, port = MM_PORT (g_object_new (MM_TYPE_PORT,
MM_PORT_DEVICE, name, MM_PORT_DEVICE, name,
MM_PORT_SUBSYS, MM_PORT_SUBSYS_NET, MM_PORT_SUBSYS, MM_PORT_SUBSYS_NET,
MM_PORT_TYPE, ptype, MM_PORT_TYPE, MM_PORT_TYPE_IGNORED,
NULL)); NULL));
}
device = mm_modem_get_device (MM_MODEM (self)); /* Net device (if any) is the preferred data port */
mm_dbg ("(%s/%s) type %s claimed by %s", if (!self->priv->data || MM_IS_AT_SERIAL_PORT (self->priv->data)) {
subsys, g_clear_object (&self->priv->data);
name, self->priv->data = g_object_ref (port);
mm_port_type_to_name (ptype),
device);
g_free (device);
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; mm_dbg ("(%s/%s) port grabbed by %s",
}
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",
subsys, subsys,
name, name,
type_name, mm_port_get_device (port));
device);
g_free (device);
} }
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 void
@@ -237,15 +367,6 @@ mm_base_modem_set_valid (MMBaseModem *self,
if (self->priv->valid != new_valid) { if (self->priv->valid != new_valid) {
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]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALID]);
} }
} }
@@ -371,6 +492,11 @@ dispose (GObject *object)
{ {
MMBaseModem *self = MM_BASE_MODEM (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) { if (self->priv->ports) {
g_hash_table_destroy (self->priv->ports); g_hash_table_destroy (self->priv->ports);
self->priv->ports = NULL; self->priv->ports = NULL;

View File

@@ -52,16 +52,20 @@ struct _MMBaseModemClass {
GType mm_base_modem_get_type (void); GType mm_base_modem_get_type (void);
gboolean mm_base_modem_grab_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name,
MMPortType suggested_type);
void mm_base_modem_release_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name);
MMPort *mm_base_modem_get_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name);
gboolean mm_base_modem_owns_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name);
MMPort *mm_base_modem_get_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name);
MMPort *mm_base_modem_add_port (MMBaseModem *self,
const gchar *subsys,
const gchar *name,
MMPortType ptype);
gboolean mm_base_modem_remove_port (MMBaseModem *self,
MMPort *port);
void mm_base_modem_set_valid (MMBaseModem *self, void mm_base_modem_set_valid (MMBaseModem *self,
gboolean valid); gboolean valid);