summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-02-16 15:57:43 +0100
committerDan Williams <dcbw@redhat.com>2012-02-25 19:50:22 -0600
commit7e406c27af9a3d2fb7266daa55d12cd0ba00f6fc (patch)
tree84752ed9ca35dba7648e2899f6f4465d6f34b66e
parent17e6f3ee8a9f5f366bc6bb21fac4d526d12b1f38 (diff)
Revert "huawei: rework probing and detection"
This reverts commit dc89c0a42d826fc3302b3d790d5161945ff7078f. Older Huawei devices like the E220 really don't like this patch, but we have a real solution in-store (see the 'ports' branch) queued up for later. So until we feel comfortable with that patch, revert the problem commit. This will change probing behavior for newer Huawei devices, but they deal better with secondary ports anyway, while the E220 is just dumb and so it needs some special help.
-rw-r--r--plugins/mm-modem-huawei-gsm.c78
-rw-r--r--plugins/mm-plugin-huawei.c230
2 files changed, 139 insertions, 169 deletions
diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c
index 124c15cb..4fc3c3f3 100644
--- a/plugins/mm-modem-huawei-gsm.c
+++ b/plugins/mm-modem-huawei-gsm.c
@@ -729,82 +729,6 @@ handle_status_change (MMAtSerialPort *port,
/*****************************************************************************/
-static void
-do_enable_power_up_done (MMGenericGsm *gsm,
- GString *response,
- GError *error,
- MMCallbackInfo *info)
-{
- if (!error) {
- MMAtSerialPort *primary;
-
- /* Enable unsolicited result codes */
- primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
-
- mm_at_serial_port_queue_command (primary, "^CURC=1", 5, NULL, NULL);
- }
-
- /* Chain up to parent */
- MM_GENERIC_GSM_CLASS (mm_modem_huawei_gsm_parent_class)->do_enable_power_up_done (gsm, NULL, error, info);
-}
-
-/*****************************************************************************/
-
-static void
-disable_unsolicited_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;
-
- /* Ignore all errors */
- mm_callback_info_schedule (info);
-}
-
-static void
-invoke_call_parent_disable_fn (MMCallbackInfo *info)
-{
- /* Note: we won't call the parent disable if info->modem is no longer
- * valid. The invoke is called always once the info gets scheduled, which
- * may happen during removed modem detection. */
- if (info->modem) {
- MMModem *parent_modem_iface;
-
- parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem));
- parent_modem_iface->disable (info->modem, (MMModemFn)info->callback, info->user_data);
- }
-}
-
-static void
-disable (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
-{
- MMAtSerialPort *primary;
- MMCallbackInfo *info;
-
- info = mm_callback_info_new_full (modem,
- invoke_call_parent_disable_fn,
- (GCallback)callback,
- user_data);
-
- primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
-
- /* Turn off unsolicited responses */
- mm_at_serial_port_queue_command (primary, "^CURC=0", 5, disable_unsolicited_done, info);
-}
-
-/*****************************************************************************/
-
static gboolean
grab_port (MMModem *modem,
const char *subsys,
@@ -933,7 +857,6 @@ static void
modem_init (MMModem *modem_class)
{
modem_class->grab_port = grab_port;
- modem_class->disable = disable;
}
static void
@@ -973,6 +896,5 @@ mm_modem_huawei_gsm_class_init (MMModemHuaweiGsmClass *klass)
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;
gsm_class->get_access_technology = get_access_technology;
- gsm_class->do_enable_power_up_done = do_enable_power_up_done;
}
diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c
index 76e2d35a..fe7ffa0e 100644
--- a/plugins/mm-plugin-huawei.c
+++ b/plugins/mm-plugin-huawei.c
@@ -15,7 +15,6 @@
*/
#include <string.h>
-#include <stdlib.h>
#include <gmodule.h>
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
@@ -29,7 +28,6 @@
#include "mm-serial-parsers.h"
#include "mm-at-serial-port.h"
#include "mm-log.h"
-#include "mm-errors.h"
G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE)
@@ -46,8 +44,6 @@ mm_plugin_create (void)
/*****************************************************************************/
-#define TAG_HUAWEI_PCUI_PORT "huawei-pcui-port"
-
#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
MM_PLUGIN_BASE_PORT_CAP_IS856 | \
@@ -74,59 +70,95 @@ probe_result (MMPluginBase *base,
mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
+#define TAG_SUPPORTS_INFO "huawei-supports-info"
+
+typedef struct {
+ MMAtSerialPort *serial;
+ guint id;
+ MMPortType ptype;
+ /* Whether or not there's already a detected modem that "owns" this port,
+ * in which case we'll claim it, but if no capabilities are detected it'll
+ * just be ignored.
+ */
+ gboolean parent_modem;
+} HuaweiSupportsInfo;
+
+static void
+huawei_supports_info_destroy (gpointer user_data)
+{
+ HuaweiSupportsInfo *info = user_data;
+
+ if (info->id)
+ g_source_remove (info->id);
+ if (info->serial)
+ g_object_unref (info->serial);
+ memset (info, 0, sizeof (HuaweiSupportsInfo));
+ g_free (info);
+}
+
static gboolean
-getportmode_response_cb (MMPluginBaseSupportsTask *task,
- GString *response,
- GError *error,
- guint32 tries,
- gboolean *out_stop,
- guint32 *out_level,
- gpointer user_data)
+probe_secondary_supported (gpointer user_data)
{
- /* If any error occurred that was not ERROR or COMMAND NOT SUPPORT then
- * retry the command.
- */
- if (error) {
- if (g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_UNKNOWN) == FALSE)
- return tries <= 4 ? TRUE : FALSE;
- } else {
- MMPlugin *plugin;
- char *p;
- int i = 0;
-
- /* Get the USB interface number of the PCUI port */
- p = strstr (response->str, "PCUI:");
- if (p)
- i = atoi (p + strlen ("PCUI:"));
-
- if (i) {
- /* Save they PCUI port number for later */
- plugin = mm_plugin_base_supports_task_get_plugin (task);
- g_assert (plugin);
- g_object_set_data (G_OBJECT (plugin), TAG_HUAWEI_PCUI_PORT, GINT_TO_POINTER (i));
- }
- }
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
+
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
- /* No error or if ^GETPORTMODE is not supported, assume success */
+ info->id = 0;
+ g_object_unref (info->serial);
+ info->serial = NULL;
+
+ /* Yay, supported, we got an unsolicited message */
+ info->ptype = MM_PORT_TYPE_SECONDARY;
+ mm_plugin_base_supports_task_complete (task, 10);
return FALSE;
}
+static void
+probe_secondary_handle_msg (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
+
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ g_source_remove (info->id);
+ info->id = g_idle_add (probe_secondary_supported, task);
+}
+
static gboolean
-curc_response_cb (MMPluginBaseSupportsTask *task,
- GString *response,
- GError *error,
- guint32 tries,
- gboolean *out_stop,
- guint32 *out_level,
- gpointer user_data)
+probe_secondary_timeout (gpointer user_data)
{
- if (error)
- return tries <= 4 ? TRUE : FALSE;
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
+ guint level = 0;
+
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ info->id = 0;
+ g_object_unref (info->serial);
+ info->serial = NULL;
+
+ /* Supported, but ignored if this port's parent device is already a modem */
+ if (info->parent_modem) {
+ info->ptype = MM_PORT_TYPE_IGNORED;
+ level = 10;
+ }
- /* No error, assume success */
+ mm_plugin_base_supports_task_complete (task, level);
return FALSE;
}
+static void
+add_regex (MMAtSerialPort *port, const char *match, gpointer user_data)
+{
+ GRegex *regex;
+
+ regex = g_regex_new (match, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, probe_secondary_handle_msg, user_data, NULL);
+ g_regex_unref (regex);
+}
+
static MMPluginSupportsResult
supports_port (MMPluginBase *base,
MMModem *existing,
@@ -137,6 +169,7 @@ supports_port (MMPluginBase *base,
const char *subsys, *name, *driver;
int usbif;
guint16 vendor = 0, product = 0;
+ guint32 existing_type = MM_MODEM_TYPE_UNKNOWN;
/* Can't do anything with non-serial ports */
port = mm_plugin_base_supports_task_get_port (task);
@@ -161,48 +194,72 @@ supports_port (MMPluginBase *base,
if (usbif < 0)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- /* The primary port (called the "modem" port in the Windows drivers) is
- * always USB interface 0, and we need to detect that interface first for
- * two reasons: (1) to disable unsolicited messages on other ports that
- * may fill up the buffer and crash the device, and (2) to attempt to get
- * the port layout for hints about what the secondary port is (called the
- * "pcui" port in Windows). Thus we probe USB interface 0 first and defer
- * probing other interfaces until we've got if0, at which point we allow
- * the other ports to be probed too.
+ /* The secondary ports don't necessarily respond correctly to probing, so
+ * we need to use the first port that does respond to probing to create the
+ * right type of mode (GSM or CDMA), and then re-check the other interfaces.
*/
if (!existing && usbif != 0)
return MM_PLUGIN_SUPPORTS_PORT_DEFER;
- if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
- level = get_level_for_capabilities (cached);
- if (level) {
- mm_plugin_base_supports_task_complete (task, level);
+ /* CDMA devices don't have problems with the secondary ports, so after
+ * ensuring we have a device by probing the first port, probe the secondary
+ * ports on CDMA devices too.
+ */
+ if (existing)
+ g_object_get (G_OBJECT (existing), MM_MODEM_TYPE, &existing_type, NULL);
+
+ if (usbif == 0 || (existing_type == MM_MODEM_TYPE_CDMA)) {
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, 100000, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ } else {
+ HuaweiSupportsInfo *info;
+ GError *error = NULL;
+
+ /* Listen for Huawei-specific unsolicited messages */
+ info = g_malloc0 (sizeof (HuaweiSupportsInfo));
+ info->parent_modem = !!existing;
+
+ info->serial = mm_at_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
+ g_object_set (G_OBJECT (info->serial), MM_PORT_CARRIER_DETECT, FALSE, NULL);
+
+ mm_at_serial_port_set_response_parser (info->serial,
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+
+ add_regex (info->serial, "\\r\\n\\^RSSI:(\\d+)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^BOOT:.+\\r\\n", task);
+ add_regex (info->serial, "\\r\\r\\^BOOT:.+\\r\\r", task);
+
+ info->id = g_timeout_add_seconds (7, probe_secondary_timeout, task);
+
+ if (!mm_serial_port_open (MM_SERIAL_PORT (info->serial), &error)) {
+ mm_warn ("(Huawei) %s: couldn't open serial port: (%d) %s",
+ name,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ huawei_supports_info_destroy (info);
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
- return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- }
- /* Turn off unsolicited messages on secondary ports until needed,
- * and try to get a port map from the modem. The response will
- * get handled in custom_init_response().
- */
- if (usbif == 0) {
- mm_plugin_base_supports_task_add_custom_init_command (task,
- "AT^CURC=0",
- 3, /* delay */
- curc_response_cb,
- NULL);
-
- mm_plugin_base_supports_task_add_custom_init_command (task,
- "AT^GETPORTMODE",
- 3, /* delay */
- getportmode_response_cb,
- NULL);
- }
+ g_object_set_data_full (G_OBJECT (task), TAG_SUPPORTS_INFO,
+ info, huawei_supports_info_destroy);
- /* Kick off a probe */
- if (mm_plugin_base_probe_port (base, task, 100000, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
@@ -262,21 +319,12 @@ grab_port (MMPluginBase *base,
}
}
} else {
+ HuaweiSupportsInfo *info;
MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
- int pcui_usbif, port_usbif;
-
- /* Any additional AT ports can be secondary ports, but we want to ensure
- * that the "pcui" port found from ^GETPORTMODE above is always set as
- * a secondary port too.
- */
-
- port_usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM");
- pcui_usbif = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (base), TAG_HUAWEI_PCUI_PORT));
- if ( (port_usbif == pcui_usbif)
- || (caps & MM_PLUGIN_BASE_PORT_CAP_GSM)
- || (caps & CAP_CDMA))
- ptype = MM_PORT_TYPE_SECONDARY;
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ if (info)
+ ptype = info->ptype;
else if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM)
ptype = MM_PORT_TYPE_QCDM;