From 14d771b90f5a7d3887e5e900d1fb4737477ad305 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Wed, 5 Feb 2014 08:38:27 +0100 Subject: Imported Upstream version 0.5.2.0 --- plugins/77-mm-ericsson-mbm.rules | 27 ++++ plugins/77-mm-nokia-port-types.rules | 39 ++++++ plugins/Makefile.am | 6 +- plugins/Makefile.in | 10 +- plugins/mm-modem-anydata-cdma.c | 6 + plugins/mm-modem-hso.c | 8 +- plugins/mm-modem-huawei-gsm.c | 99 +++---------- plugins/mm-modem-mbm.c | 4 +- plugins/mm-modem-nokia.c | 9 ++ plugins/mm-modem-novatel-cdma.c | 16 +-- plugins/mm-modem-novatel-gsm.c | 3 +- plugins/mm-modem-samsung-gsm.c | 4 +- plugins/mm-modem-sierra-gsm.c | 261 +++++++++++++++++++++++++++++++++-- plugins/mm-modem-wavecom-gsm.c | 121 ++++++++++------ plugins/mm-modem-x22x-gsm.c | 3 +- plugins/mm-modem-zte.c | 6 +- plugins/mm-plugin-huawei.c | 237 +++++++++++++++++++------------ plugins/mm-plugin-longcheer.c | 3 +- plugins/mm-plugin-nokia.c | 33 ++++- plugins/mm-plugin-x22x.c | 3 +- 20 files changed, 635 insertions(+), 263 deletions(-) create mode 100644 plugins/77-mm-nokia-port-types.rules (limited to 'plugins') diff --git a/plugins/77-mm-ericsson-mbm.rules b/plugins/77-mm-ericsson-mbm.rules index 8c03acf..897bd5c 100644 --- a/plugins/77-mm-ericsson-mbm.rules +++ b/plugins/77-mm-ericsson-mbm.rules @@ -30,6 +30,27 @@ ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190b", ENV{ID_MM_ERICSSON_MBM}="1" ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190d", ENV{ID_MM_ERICSSON_MBM}="1" ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1911", ENV{ID_MM_ERICSSON_MBM}="1" +# Ericsson H5321gw +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1919", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson H5321w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191d", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson F5321gw +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1917", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson F5321w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191b", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson C5621gw +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191f", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson C5621w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1921", ENV{ID_MM_ERICSSON_MBM}="1" + +# Ericsson C3304w +ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1928", ENV{ID_MM_ERICSSON_MBM}="1" + # Sony-Ericsson MD300 ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0cf", ENV{ID_MM_ERICSSON_MBM}="1" @@ -39,6 +60,9 @@ ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0e1", ENV{ID_MM_ERICSSON_MBM}="1" # Sony-Ericsson MD400G ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d103", ENV{ID_MM_ERICSSON_MBM}="1" +# Dell 5560 +ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818e", ENV{ID_MM_ERICSSON_MBM}="1" + # Dell 5550 ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818d", ENV{ID_MM_ERICSSON_MBM}="1" @@ -59,6 +83,9 @@ ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="271d", ENV{ID_MM_ERICSSON_MBM}="1" # HP hs2320 Mobile Broadband Module ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="261d", ENV{ID_MM_ERICSSON_MBM}="1" +# HP hs2340 Mobile Broadband Module +ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="3a1d", ENV{ID_MM_ERICSSON_MBM}="1" + # HP lc2000 Mobile Broadband Module ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="301d", ENV{ID_MM_ERICSSON_MBM}="1" diff --git a/plugins/77-mm-nokia-port-types.rules b/plugins/77-mm-nokia-port-types.rules new file mode 100644 index 0000000..560f3ce --- /dev/null +++ b/plugins/77-mm-nokia-port-types.rules @@ -0,0 +1,39 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="add|change", GOTO="mm_nokia_port_types_end" +SUBSYSTEM!="tty", GOTO="mm_nokia_port_types_end" + +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0421", GOTO="mm_nokia_port_types_vendorcheck" +GOTO="mm_nokia_port_types_end" + +LABEL="mm_nokia_port_types_vendorcheck" +SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" + +# For Nokia Internet Sticks (CS-xx) the modem/PPP port appears to always be USB interface 1 + +ATTRS{idProduct}=="060D", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0611", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="061A", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="061B", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="061F", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0620", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0623", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0624", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="0625", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="062A", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="062E", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +ATTRS{idProduct}=="062F", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_NOKIA_PORT_TYPE_MODEM}="1" + +LABEL="mm_nokia_port_types_end" + diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 47fc3b0..2b71246 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -189,6 +189,9 @@ libmm_plugin_sierra_la_LDFLAGS = \ -module \ -avoid-version +libmm_plugin_sierra_la_LIBADD = \ + $(builddir)/libicera-utils.la + # Wavecom (Sierra Airlink) libmm_plugin_wavecom_la_SOURCES = \ @@ -384,7 +387,8 @@ udevrules_DATA = \ 77-mm-zte-port-types.rules \ 77-mm-longcheer-port-types.rules \ 77-mm-simtech-port-types.rules \ - 77-mm-x22x-port-types.rules + 77-mm-x22x-port-types.rules \ + 77-mm-nokia-port-types.rules BUILT_SOURCES = \ mm-modem-gsm-hso-glue.h diff --git a/plugins/Makefile.in b/plugins/Makefile.in index df6b5e3..b2dea3f 100644 --- a/plugins/Makefile.in +++ b/plugins/Makefile.in @@ -46,7 +46,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -204,7 +204,7 @@ libmm_plugin_samsung_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libmm_plugin_samsung_la_LDFLAGS) \ $(LDFLAGS) -o $@ -libmm_plugin_sierra_la_LIBADD = +libmm_plugin_sierra_la_DEPENDENCIES = $(builddir)/libicera-utils.la am_libmm_plugin_sierra_la_OBJECTS = \ libmm_plugin_sierra_la-mm-plugin-sierra.lo \ libmm_plugin_sierra_la-mm-modem-sierra-gsm.lo \ @@ -648,6 +648,9 @@ libmm_plugin_sierra_la_LDFLAGS = \ -module \ -avoid-version +libmm_plugin_sierra_la_LIBADD = \ + $(builddir)/libicera-utils.la + # Wavecom (Sierra Airlink) libmm_plugin_wavecom_la_SOURCES = \ @@ -843,7 +846,8 @@ udevrules_DATA = \ 77-mm-zte-port-types.rules \ 77-mm-longcheer-port-types.rules \ 77-mm-simtech-port-types.rules \ - 77-mm-x22x-port-types.rules + 77-mm-x22x-port-types.rules \ + 77-mm-nokia-port-types.rules BUILT_SOURCES = \ mm-modem-gsm-hso-glue.h diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c index 7b6b37a..d26d3ec 100644 --- a/plugins/mm-modem-anydata-cdma.c +++ b/plugins/mm-modem-anydata-cdma.c @@ -183,6 +183,9 @@ evdo_state_done (MMAtSerialPort *port, } } + g_match_info_free (match_info); + g_regex_unref (r); + done: mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state); mm_callback_info_schedule (info); @@ -254,6 +257,9 @@ state_done (MMAtSerialPort *port, } } + g_match_info_free (match_info); + g_regex_unref (r); + mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); /* Try for EVDO state too */ diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c index e3d4dce..5d4201c 100644 --- a/plugins/mm-modem-hso.c +++ b/plugins/mm-modem-hso.c @@ -778,7 +778,12 @@ grab_port (MMModem *modem, goto out; if (MM_IS_AT_SERIAL_PORT (port)) { - g_object_set (G_OBJECT (port), MM_SERIAL_PORT_SEND_DELAY, (guint64) 0, NULL); + g_object_set (G_OBJECT (port), + MM_SERIAL_PORT_SEND_DELAY, (guint64) 0, + /* built-in echo removal conflicts with unsolicited _OWANCALL + * messages, which are not prefixed. */ + MM_AT_SERIAL_PORT_REMOVE_ECHO, FALSE, + NULL); if (ptype == MM_PORT_TYPE_PRIMARY) { GRegex *regex; @@ -854,4 +859,3 @@ mm_modem_hso_class_init (MMModemHsoClass *klass) gsm_class->get_allowed_mode = get_allowed_mode; gsm_class->get_access_technology = get_access_technology; } - diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c index 5f4c2fb..4fc3c3f 100644 --- a/plugins/mm-modem-huawei-gsm.c +++ b/plugins/mm-modem-huawei-gsm.c @@ -599,9 +599,9 @@ send_huawei_cpin_done (MMAtSerialPort *port, mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL); - g_match_info_free (match_info); - done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_serial_port_close (MM_SERIAL_PORT (port)); @@ -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, @@ -888,6 +812,16 @@ ussd_encode (MMModemGsmUssd *self, const char* command, guint *scheme) *scheme = MM_MODEM_GSM_USSD_SCHEME_7BIT; gsm = mm_charset_utf8_to_unpacked_gsm (command, &len); + + /* If command is a multiple of 7 characters long, Huawei firmwares + * apparently want that padded. Maybe all modems? + */ + if (len % 7 == 0) { + gsm = g_realloc (gsm, len + 1); + gsm[len] = 0x0d; + len++; + } + packed = gsm_pack (gsm, len, 0, &packed_len); hex = utils_bin2hexstr (packed, packed_len); g_free (packed); @@ -906,8 +840,11 @@ ussd_decode (MMModemGsmUssd *self, const char* reply, guint scheme) guint32 unpacked_len; bin = utils_hexstr2bin (reply, &bin_len); - unpacked = gsm_unpack ((guint8*)bin, bin_len, 0, &unpacked_len); - utf8 = (char*)mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len); + unpacked = gsm_unpack ((guint8*) bin, (bin_len * 8) / 7, 0, &unpacked_len); + /* if the last character in a 7-byte block is padding, then drop it */ + if ((bin_len % 7 == 0) && (unpacked[unpacked_len - 1] == 0x0d)) + unpacked_len--; + utf8 = (char*) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len); g_free (bin); g_free (unpacked); @@ -920,7 +857,6 @@ static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; - modem_class->disable = disable; } static void @@ -960,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-modem-mbm.c b/plugins/mm-modem-mbm.c index 7aa8a01..ab39ff6 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -730,7 +730,9 @@ enap_poll_response (MMAtSerialPort *port, count = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mbm-enap-poll-count")); - if (sscanf (response->str, "*ENAP: %d", &state) == 1 && state == 1) { + if ( response + && sscanf (response->str, "*ENAP: %d", &state) == 1 + && state == 1) { /* Success! Connected... */ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info); return; diff --git a/plugins/mm-modem-nokia.c b/plugins/mm-modem-nokia.c index 56f4c1b..9476f61 100644 --- a/plugins/mm-modem-nokia.c +++ b/plugins/mm-modem-nokia.c @@ -120,6 +120,11 @@ get_property (GObject *object, guint prop_id, case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD: g_value_set_string (value, ""); break; + case MM_GENERIC_GSM_PROP_INIT_CMD: + /* When initializing a Nokia phone, first enable the echo, + * and then disable it, so that we get it properly disabled */ + g_value_set_string (value, "Z E1 E0 V1"); + break; default: break; } @@ -135,6 +140,10 @@ mm_modem_nokia_class_init (MMModemNokiaClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_INIT_CMD, + MM_GENERIC_GSM_INIT_CMD); + g_object_class_override_property (object_class, MM_GENERIC_GSM_PROP_POWER_UP_CMD, MM_GENERIC_GSM_POWER_UP_CMD); diff --git a/plugins/mm-modem-novatel-cdma.c b/plugins/mm-modem-novatel-cdma.c index c1f4151..77d6bee 100644 --- a/plugins/mm-modem-novatel-cdma.c +++ b/plugins/mm-modem-novatel-cdma.c @@ -181,7 +181,7 @@ get_signal_quality (MMModemCdma *modem, /*****************************************************************************/ static void -parse_modem_snapshot (MMCallbackInfo *info, QCDMResult *result) +parse_modem_snapshot (MMCallbackInfo *info, QcdmResult *result) { MMModemCdmaRegistrationState evdo_state, cdma1x_state, new_state; guint8 eri = 0; @@ -193,7 +193,7 @@ parse_modem_snapshot (MMCallbackInfo *info, QCDMResult *result) cdma1x_state = mm_generic_cdma_query_reg_state_get_callback_1x_state (info); /* Roaming? */ - if (qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &eri)) { + if (qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &eri)) { char *str; gboolean roaming = FALSE; @@ -216,7 +216,7 @@ reg_nwsnap_6500_cb (MMQcdmSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; - QCDMResult *result; + QcdmResult *result; if (!error) { result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, NULL); @@ -235,20 +235,18 @@ reg_nwsnap_6800_cb (MMQcdmSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; - QCDMResult *result; + QcdmResult *result; GByteArray *nwsnap; if (error) goto done; /* Parse the response */ - result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, &info->error); + result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, NULL); if (!result) { - g_clear_error (&info->error); - /* Try for MSM6500 */ nwsnap = g_byte_array_sized_new (25); - nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6500, NULL); + nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6500); g_assert (nwsnap->len); mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6500_cb, info); return; @@ -282,7 +280,7 @@ query_registration_state (MMGenericCdma *cdma, /* Try MSM6800 first since newer cards use that */ nwsnap = g_byte_array_sized_new (25); - nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6800, NULL); + nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6800); g_assert (nwsnap->len); mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6800_cb, info); } diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c index 5d78db7..706664c 100644 --- a/plugins/mm-modem-novatel-gsm.c +++ b/plugins/mm-modem-novatel-gsm.c @@ -198,8 +198,6 @@ parse_nwrat_response (GString *response, mode = atoi (str); g_free (str); - g_match_info_free (match_info); - if (mode < 0 || mode > 2) { g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to parse mode/tech response"); @@ -219,6 +217,7 @@ parse_nwrat_response (GString *response, success = TRUE; out: + g_match_info_free (match_info); g_regex_unref (r); return success; } diff --git a/plugins/mm-modem-samsung-gsm.c b/plugins/mm-modem-samsung-gsm.c index f2d339b..05cebe4 100755 --- a/plugins/mm-modem-samsung-gsm.c +++ b/plugins/mm-modem-samsung-gsm.c @@ -357,9 +357,9 @@ send_samsung_pinnum_done (MMAtSerialPort *port, mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL); - g_match_info_free (match_info); - done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_serial_port_close (MM_SERIAL_PORT (port)); diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c index 551142e..1a9b735 100644 --- a/plugins/mm-modem-sierra-gsm.c +++ b/plugins/mm-modem-sierra-gsm.c @@ -25,12 +25,16 @@ #include "mm-modem-simple.h" #include "mm-callback-info.h" #include "mm-modem-helpers.h" +#include "mm-log.h" +#include "mm-modem-icera.h" static void modem_init (MMModem *modem_class); +static void modem_icera_init (MMModemIcera *icera_class); static void modem_simple_init (MMModemSimple *class); G_DEFINE_TYPE_EXTENDED (MMModemSierraGsm, mm_modem_sierra_gsm, MM_TYPE_GENERIC_GSM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_ICERA, modem_icera_init) G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init)) #define MM_MODEM_SIERRA_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_SIERRA_GSM, MMModemSierraGsmPrivate)) @@ -40,6 +44,8 @@ typedef struct { gboolean has_net; char *username; char *password; + gboolean is_icera; + MMModemIceraPrivate *icera; } MMModemSierraGsmPrivate; MMModem * @@ -49,17 +55,23 @@ mm_modem_sierra_gsm_new (const char *device, guint32 vendor, guint32 product) { + MMModem *modem; + 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_MODEM_SIERRA_GSM, - MM_MODEM_MASTER_DEVICE, device, - MM_MODEM_DRIVER, driver, - MM_MODEM_PLUGIN, plugin, - MM_MODEM_HW_VID, vendor, - MM_MODEM_HW_PID, product, - NULL)); + modem = (MMModem *) g_object_new (MM_TYPE_MODEM_SIERRA_GSM, + MM_MODEM_MASTER_DEVICE, device, + MM_MODEM_DRIVER, driver, + MM_MODEM_PLUGIN, plugin, + MM_MODEM_HW_VID, vendor, + MM_MODEM_HW_PID, product, + NULL); + if (modem) + MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem)->icera = mm_modem_icera_init_private (); + + return modem; } /*****************************************************************************/ @@ -72,7 +84,7 @@ get_allowed_mode_done (MMAtSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; GRegex *r = NULL; - GMatchInfo *match_info; + GMatchInfo *match_info = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -127,6 +139,8 @@ get_allowed_mode_done (MMAtSerialPort *port, } done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_callback_info_schedule (info); @@ -137,9 +151,15 @@ get_allowed_mode (MMGenericGsm *gsm, MMModemUIntFn callback, gpointer user_data) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (gsm); MMCallbackInfo *info; MMAtSerialPort *primary; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_allowed_mode (MM_MODEM_ICERA (self), callback, user_data); + return; + } + info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data); /* Sierra secondary ports don't have full AT command interpreters */ @@ -179,11 +199,17 @@ set_allowed_mode (MMGenericGsm *gsm, MMModemFn callback, gpointer user_data) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (gsm); MMCallbackInfo *info; MMAtSerialPort *primary; char *command; int idx = 0; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_set_allowed_mode (MM_MODEM_ICERA (self), mode, callback, user_data); + return; + } + info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data); /* Sierra secondary ports don't have full AT command interpreters */ @@ -251,9 +277,15 @@ get_access_technology (MMGenericGsm *modem, MMModemUIntFn callback, gpointer user_data) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (modem); MMAtSerialPort *port; MMCallbackInfo *info; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_access_technology (MM_MODEM_ICERA (self), callback, user_data); + return; + } + info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); port = mm_generic_gsm_get_best_at_port (modem, &info->error); @@ -353,6 +385,28 @@ error: /* Modem class override functions */ /*****************************************************************************/ +static void +icera_check_cb (MMModem *modem, + guint32 result, + GError *error, + gpointer user_data) +{ + if (!error) { + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (user_data); + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self); + + if (result) { + priv->is_icera = TRUE; + g_object_set (G_OBJECT (modem), + MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_STATIC, + NULL); + + /* Turn on unsolicited network state messages */ + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (modem), TRUE); + } + } +} + static gboolean sierra_enabled (gpointer user_data) { @@ -365,6 +419,8 @@ sierra_enabled (gpointer user_data) modem = MM_GENERIC_GSM (info->modem); priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem); priv->enable_wait_id = 0; + mm_modem_icera_is_icera (MM_MODEM_ICERA (modem), icera_check_cb, MM_MODEM_SIERRA_GSM (modem)); + MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_enable_power_up_done (modem, NULL, NULL, info); } return FALSE; @@ -391,6 +447,64 @@ real_do_enable_power_up_done (MMGenericGsm *gsm, priv->enable_wait_id = g_timeout_add_seconds (10, sierra_enabled, info); } +static void +get_current_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + guint needed = FALSE; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (info)) + return; + + /* On error, just assume we don't need the power-up command */ + if (!error) { + const gchar *p; + + p = mm_strip_tag (response->str, "+CFUN:"); + if (p && *p == '1') { + /* If reported functionality status is '1', then we do not need to + * issue the power-up command. Otherwise, do it. */ + mm_dbg ("Already in full functionality status, skipping power-up command"); + } else { + needed = TRUE; + mm_warn ("Not in full functionality status, power-up command is needed."); + } + } else + mm_warn ("Failed checking if power-up command is needed: '%s'. " + "Will assume it isn't.", + error->message); + + /* Set result and schedule */ + mm_callback_info_set_result (info, + GUINT_TO_POINTER (needed), + NULL); + mm_callback_info_schedule (info); +} + +static void +do_enable_power_up_check_needed (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + /* Get port */ + primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + /* Get current functionality status */ + mm_dbg ("Getting current functionality status..."); + mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info); +} + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -422,6 +536,9 @@ grab_port (MMModem *modem, regex = g_regex_new ("\\r\\n\\+PACSP0\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL); g_regex_unref (regex); + + /* Add Icera-specific handlers */ + mm_modem_icera_register_unsolicted_handlers (MM_MODEM_ICERA (gsm), MM_AT_SERIAL_PORT (port)); } else if (mm_port_get_subsys (port) == MM_PORT_SUBSYS_NET) { MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm)->has_net = TRUE; g_object_set (G_OBJECT (gsm), MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP, NULL); @@ -554,6 +671,11 @@ do_connect (MMModem *modem, MMCallbackInfo *info; MMAtSerialPort *port; + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem)->is_icera) { + mm_modem_icera_do_connect (MM_MODEM_ICERA (modem), number, callback, user_data); + return; + } + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); info = mm_callback_info_new (modem, callback, user_data); @@ -572,6 +694,21 @@ do_connect (MMModem *modem, mm_at_serial_port_queue_command (port, "+CGATT=1", 10, ps_attach_done, info); } +static void +get_ip4_config (MMModem *modem, + MMModemIp4Fn callback, + gpointer user_data) +{ + MMModem *parent_iface; + + if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem)->is_icera) { + mm_modem_icera_get_ip4_config (MM_MODEM_ICERA (modem), callback, user_data); + } else { + parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); + parent_iface->get_ip4_config (modem, callback, user_data); + } +} + static void clear_user_pass (MMModemSierraGsm *self) { @@ -589,9 +726,17 @@ do_disconnect (MMGenericGsm *gsm, MMModemFn callback, gpointer user_data) { - clear_user_pass (MM_MODEM_SIERRA_GSM (gsm)); + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (gsm); + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self); - if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm)->has_net) { + if (priv->is_icera) { + mm_modem_icera_do_disconnect (gsm, cid, callback, user_data); + return; + } + + clear_user_pass (self); + + if (priv->has_net) { MMAtSerialPort *primary; char *command; @@ -607,6 +752,68 @@ do_disconnect (MMGenericGsm *gsm, MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_disconnect (gsm, cid, callback, user_data); } + +/*****************************************************************************/ + +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 +do_disable (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem); + 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 */ + if (priv->is_icera) { + mm_modem_icera_cleanup (MM_MODEM_ICERA (modem)); + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (modem), FALSE); + } + + /* Random command to ensure unsolicited message disable completes */ + mm_at_serial_port_queue_command (primary, "E0", 5, disable_unsolicited_done, info); +} + /*****************************************************************************/ /* Simple Modem class override functions */ /*****************************************************************************/ @@ -640,9 +847,13 @@ simple_connect (MMModemSimple *simple, MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMModemSimple *parent_iface; - clear_user_pass (MM_MODEM_SIERRA_GSM (simple)); - priv->username = simple_dup_string_property (properties, "username", &info->error); - priv->password = simple_dup_string_property (properties, "password", &info->error); + if (priv->is_icera) { + mm_modem_icera_simple_connect (MM_MODEM_ICERA (simple), properties); + } else { + clear_user_pass (MM_MODEM_SIERRA_GSM (simple)); + priv->username = simple_dup_string_property (properties, "username", &info->error); + priv->password = simple_dup_string_property (properties, "password", &info->error); + } parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple)); parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info); @@ -650,11 +861,27 @@ simple_connect (MMModemSimple *simple, /*****************************************************************************/ +static MMModemIceraPrivate * +get_icera_private (MMModemIcera *icera) +{ + return MM_MODEM_SIERRA_GSM_GET_PRIVATE (icera)->icera; +} + +/*****************************************************************************/ + static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; modem_class->connect = do_connect; + modem_class->disable = do_disable; + modem_class->get_ip4_config = get_ip4_config; +} + +static void +modem_icera_init (MMModemIcera *icera) +{ + icera->get_private = get_icera_private; } static void @@ -671,12 +898,15 @@ mm_modem_sierra_gsm_init (MMModemSierraGsm *self) static void dispose (GObject *object) { - MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (object); + MMModemSierraGsm *self = MM_MODEM_SIERRA_GSM (object); + MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self); if (priv->enable_wait_id) g_source_remove (priv->enable_wait_id); - clear_user_pass (MM_MODEM_SIERRA_GSM (object)); + mm_modem_icera_dispose_private (MM_MODEM_ICERA (self)); + + clear_user_pass (self); } static void @@ -689,6 +919,7 @@ mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass) g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate)); object_class->dispose = dispose; + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = real_do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c index c66637c..3bfcdbe 100644 --- a/plugins/mm-modem-wavecom-gsm.c +++ b/plugins/mm-modem-wavecom-gsm.c @@ -218,15 +218,20 @@ get_property (GObject *object, { switch (prop_id) { case MM_GENERIC_GSM_PROP_POWER_UP_CMD: - /* Wavecom doesn't like CFUN=1, it will reset the whole software stack, - * including the USB connection and therefore connection would get - * closed */ - g_value_set_string (value, ""); + /* Try to go to full functionality mode without rebooting the system. + * Works well if we previously switched off the power with CFUN=4 + */ + g_value_set_string (value, "+CFUN=1,0"); break; case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD: /* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */ g_value_set_string (value, "+IFC=2,2"); break; + case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD: + /* Use AT+CFUN=4 for power down. It will stop the RF (IMSI detach), and + * keeps access to the SIM */ + g_value_set_string (value, "+CFUN=4"); + break; default: break; } @@ -869,7 +874,7 @@ set_highest_ms_class_cb (MMAtSerialPort *port, } /* All done without errors! */ - mm_dbg ("[5/5] All done"); + mm_dbg ("[4/4] All done"); enable_complete (MM_GENERIC_GSM (info->modem), NULL, info); } @@ -975,7 +980,7 @@ get_current_ms_class_cb (MMAtSerialPort *port, } /* Next, set highest mobile station class possible */ - mm_dbg ("[4/5] Ensuring highest MS class..."); + mm_dbg ("[3/4] Ensuring highest MS class..."); set_highest_ms_class (port, info); } @@ -1039,19 +1044,18 @@ get_supported_ms_classes_cb (MMAtSerialPort *port, } /* Next, query for current MS class */ - mm_dbg ("[3/5] Getting current MS class..."); + mm_dbg ("[2/4] Getting current MS class..."); mm_at_serial_port_queue_command (port, "+CGCLASS?", 3, get_current_ms_class_cb, info); } static void -get_current_functionality_status_cb (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +do_enable_power_up_done (MMGenericGsm *gsm, + GString *response, + GError *error, + MMCallbackInfo *info) { - MMCallbackInfo *info = user_data; - const gchar *p; - GError *inner_error; + MMAtSerialPort *port; + GError *inner_error = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -1059,57 +1063,79 @@ get_current_functionality_status_cb (MMAtSerialPort *port, return; if (error) { - enable_complete (MM_GENERIC_GSM (info->modem), error, info); + enable_complete (gsm, error, info); return; } - p = mm_strip_tag (response->str, "+CFUN:"); - if (!p || *p != '1') { - /* Reported functionality status MUST be '1'. Otherwise, RF is probably - * switched off. */ - inner_error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "Unexpected functionality status: '%c'. ", - p ? *p :' '); - enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info); + /* Get port */ + port = mm_generic_gsm_get_best_at_port (gsm, &inner_error); + if (!port) { + enable_complete (gsm, inner_error, info); g_error_free (inner_error); + return; } - /* Nex, query for supported MS classes */ - mm_dbg ("[2/5] Getting supported MS classes..."); + mm_dbg ("[1/4] Getting supported MS classes..."); mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info); } static void -do_enable_power_up_done (MMGenericGsm *gsm, - GString *response, - GError *error, - MMCallbackInfo *info) +get_current_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) { - MMAtSerialPort *port; - GError *inner_error = NULL; + MMCallbackInfo *info = user_data; + guint needed = FALSE; /* If the modem has already been removed, return without * scheduling callback */ if (mm_callback_info_check_modem_removed (info)) return; - if (error) { - enable_complete (gsm, error, info); - return; - } + /* On error, just assume we don't need the power-up command */ + if (!error) { + const gchar *p; + + p = mm_strip_tag (response->str, "+CFUN:"); + if (p && *p == '1') { + /* If reported functionality status is '1', then we do not need to + * issue the power-up command. Otherwise, do it. */ + mm_dbg ("Already in full functionality status, skipping power-up command"); + } else { + needed = TRUE; + mm_warn ("Not in full functionality status, power-up command is needed. " + "Note that it may reboot the modem."); + } + } else + mm_warn ("Failed checking if power-up command is needed: '%s'. " + "Will assume it isn't.", + error->message); + + /* Set result and schedule */ + mm_callback_info_set_result (info, + GUINT_TO_POINTER (needed), + NULL); + mm_callback_info_schedule (info); +} + +static void +do_enable_power_up_check_needed (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); /* Get port */ - port = mm_generic_gsm_get_best_at_port (gsm, &inner_error); - if (!port) { - enable_complete (gsm, inner_error, info); - g_error_free (inner_error); - return; - } + primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); - /* Next, get current functionality status */ - mm_dbg ("[1/5] Getting current functionality status..."); - mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_current_functionality_status_cb, info); + /* Get current functionality status */ + mm_dbg ("Getting current functionality status..."); + mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info); } /*****************************************************************************/ @@ -1158,6 +1184,11 @@ mm_modem_wavecom_gsm_class_init (MMModemWavecomGsmClass *klass) MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD, MM_GENERIC_GSM_FLOW_CONTROL_CMD); + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_POWER_DOWN_CMD, + MM_GENERIC_GSM_POWER_DOWN_CMD); + + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; diff --git a/plugins/mm-modem-x22x-gsm.c b/plugins/mm-modem-x22x-gsm.c index 012733d..a31cd36 100644 --- a/plugins/mm-modem-x22x-gsm.c +++ b/plugins/mm-modem-x22x-gsm.c @@ -81,8 +81,6 @@ parse_syssel_response (GString *response, mode = atoi (str); g_free (str); - g_match_info_free (match_info); - if (mode < 0 || mode > 2) { g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to parse mode/tech response"); @@ -102,6 +100,7 @@ parse_syssel_response (GString *response, success = TRUE; out: + g_match_info_free (match_info); g_regex_unref (r); return success; } diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c index 6c9f395..88ef734 100644 --- a/plugins/mm-modem-zte.c +++ b/plugins/mm-modem-zte.c @@ -105,7 +105,7 @@ get_allowed_mode_done (MMAtSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; GRegex *r = NULL; - GMatchInfo *match_info; + GMatchInfo *match_info = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -138,8 +138,6 @@ get_allowed_mode_done (MMAtSerialPort *port, pref_acq = atoi (str); g_free (str); - g_match_info_free (match_info); - if (cm_mode < 0 || cm_mode > 2 || pref_acq < 0 || pref_acq > 2) { info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, @@ -164,6 +162,8 @@ get_allowed_mode_done (MMAtSerialPort *port, } done: + if (match_info) + g_match_info_free (match_info); if (r) g_regex_unref (r); mm_callback_info_schedule (info); diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c index aef3c52..fe7ffa0 100644 --- a/plugins/mm-plugin-huawei.c +++ b/plugins/mm-plugin-huawei.c @@ -15,7 +15,6 @@ */ #include -#include #include #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, @@ -134,9 +166,10 @@ supports_port (MMPluginBase *base, { GUdevDevice *port; guint32 cached = 0, level; - const char *subsys, *name; + 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); @@ -152,52 +185,81 @@ supports_port (MMPluginBase *base, if (vendor != 0x12d1) return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + /* The Gobi driver should claim Huawei Gobi modems */ + driver = mm_plugin_base_supports_task_get_driver (task); + if (g_strcmp0 (driver, "qcserial") == 0) + return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM"); 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; } @@ -257,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; diff --git a/plugins/mm-plugin-longcheer.c b/plugins/mm-plugin-longcheer.c index 5f773a3..89a6138 100644 --- a/plugins/mm-plugin-longcheer.c +++ b/plugins/mm-plugin-longcheer.c @@ -72,12 +72,13 @@ custom_init_response_cb (MMPluginBaseSupportsTask *task, guint32 *out_level, gpointer user_data) { - const char *p = response->str; + const char *p; if (error) return tries <= 4 ? TRUE : FALSE; /* Note the lack of a ':' on the GMR; the X200 doesn't send one */ + g_assert (response); p = mm_strip_tag (response->str, "AT+GMR"); if (*p == 'L') { /* X200 modems have a GMR firmware revision that starts with 'L', and diff --git a/plugins/mm-plugin-nokia.c b/plugins/mm-plugin-nokia.c index 28e9022..de05c2d 100644 --- a/plugins/mm-plugin-nokia.c +++ b/plugins/mm-plugin-nokia.c @@ -59,6 +59,22 @@ probe_result (MMPluginBase *base, mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities)); } +static gboolean +custom_init_response_cb (MMPluginBaseSupportsTask *task, + GString *response, + GError *error, + guint32 tries, + gboolean *out_stop, + guint32 *out_level, + gpointer user_data) +{ + if (error) + return tries <= 4 ? TRUE : FALSE; + + /* No error, assume success */ + return FALSE; +} + static MMPluginSupportsResult supports_port (MMPluginBase *base, MMModem *existing, @@ -92,6 +108,12 @@ supports_port (MMPluginBase *base, return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; } + mm_plugin_base_supports_task_add_custom_init_command (task, + "ATE1 E0", + 3, + custom_init_response_cb, + NULL); + /* Otherwise kick off a probe */ if (mm_plugin_base_probe_port (base, task, 100000, NULL)) return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; @@ -110,6 +132,7 @@ grab_port (MMPluginBase *base, const char *name, *subsys, *devfile, *sysfs_path; guint32 caps; guint16 vendor = 0, product = 0; + MMPortType ptype = MM_PORT_TYPE_UNKNOWN; port = mm_plugin_base_supports_task_get_port (task); g_assert (port); @@ -128,6 +151,12 @@ grab_port (MMPluginBase *base, return NULL; } + /* Look for port type hints */ + if (g_udev_device_get_property_as_boolean (port, "ID_MM_NOKIA_PORT_TYPE_MODEM")) + ptype = MM_PORT_TYPE_PRIMARY; + else if (g_udev_device_get_property_as_boolean (port, "ID_MM_NOKIA_PORT_TYPE_AUX")) + ptype = MM_PORT_TYPE_SECONDARY; + caps = mm_plugin_base_supports_task_get_probed_capabilities (task); sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task); if (!existing) { @@ -148,14 +177,14 @@ grab_port (MMPluginBase *base, } if (modem) { - if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) { + if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) { g_object_unref (modem); return NULL; } } } else if (get_level_for_capabilities (caps)) { modem = existing; - if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) + if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) return NULL; } diff --git a/plugins/mm-plugin-x22x.c b/plugins/mm-plugin-x22x.c index 3be6731..a76a919 100644 --- a/plugins/mm-plugin-x22x.c +++ b/plugins/mm-plugin-x22x.c @@ -70,12 +70,13 @@ custom_init_response_cb (MMPluginBaseSupportsTask *task, guint32 *out_level, gpointer user_data) { - const char *p = response->str; + const char *p; if (error) return tries <= 4 ? TRUE : FALSE; /* Note the lack of a ':' on the GMR; the X200 doesn't send one */ + g_assert (response); p = mm_strip_tag (response->str, "AT+GMR"); if (*p != 'L') { /* X200 modems have a GMR firmware revision that starts with 'L', and -- cgit v1.2.3