diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/77-mm-zte-port-types.rules | 15 | ||||
-rw-r--r-- | plugins/Makefile.am | 22 | ||||
-rw-r--r-- | plugins/mm-modem-anydata-cdma.c | 28 | ||||
-rw-r--r-- | plugins/mm-modem-huawei-cdma.c | 7 | ||||
-rw-r--r-- | plugins/mm-modem-huawei-gsm.c | 85 | ||||
-rw-r--r-- | plugins/mm-modem-icera.c | 794 | ||||
-rw-r--r-- | plugins/mm-modem-icera.h | 89 | ||||
-rw-r--r-- | plugins/mm-modem-mbm.c | 36 | ||||
-rw-r--r-- | plugins/mm-modem-zte.c | 200 | ||||
-rw-r--r-- | plugins/mm-plugin-generic.c | 9 | ||||
-rw-r--r-- | plugins/mm-plugin-huawei.c | 9 | ||||
-rw-r--r-- | plugins/mm-plugin-mbm.c | 2 | ||||
-rw-r--r-- | plugins/mm-plugin-zte.c | 21 |
13 files changed, 1237 insertions, 80 deletions
diff --git a/plugins/77-mm-zte-port-types.rules b/plugins/77-mm-zte-port-types.rules index bc6f05a9..072154ce 100644 --- a/plugins/77-mm-zte-port-types.rules +++ b/plugins/77-mm-zte-port-types.rules @@ -78,6 +78,9 @@ ATTRS{idProduct}=="0033", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}= ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0039", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0039", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" @@ -93,9 +96,15 @@ ATTRS{idProduct}=="0049", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}= ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0054", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0054", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0057", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0057", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" @@ -108,9 +117,15 @@ ATTRS{idProduct}=="0064", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_AUX}= ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0082", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0082", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0108", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0108", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0113", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0113", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 9f85d54f..dd58b943 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,3 +1,24 @@ + +########################## +# Icera-specific support # +########################## + +noinst_LTLIBRARIES = libicera-utils.la + +libicera_utils_la_SOURCES = \ + mm-modem-icera.c \ + mm-modem-icera.h + +libicera_utils_la_CPPFLAGS = \ + $(MM_CFLAGS) \ + $(GUDEV_CFLAGS) \ + -I$(top_srcdir)/src + +libicera_utils_la_LIBADD = \ + $(GUDEV_LDFLAGS) + +######################################## + pkglib_LTLIBRARIES = \ libmm-plugin-generic.la \ libmm-plugin-moto-c.la \ @@ -220,6 +241,7 @@ libmm_plugin_zte_la_CPPFLAGS = \ libmm_plugin_zte_la_LDFLAGS = \ $(GUDEV_LDFLAGS) \ + $(builddir)/libicera-utils.la \ -module \ -avoid-version diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c index 3bf15ed8..0e7e65c5 100644 --- a/plugins/mm-modem-anydata-cdma.c +++ b/plugins/mm-modem-anydata-cdma.c @@ -28,6 +28,7 @@ #include "mm-callback-info.h" #include "mm-serial-port.h" #include "mm-serial-parsers.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); @@ -140,7 +141,7 @@ evdo_state_done (MMAtSerialPort *port, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { /* Parse error; warn about it and assume EVDO is not available */ - g_warning ("AnyDATA(%s): *HSTATE parse regex creation failed.", __func__); + mm_warn ("ANYDATA: *HSTATE parse regex creation failed."); goto done; } @@ -167,7 +168,7 @@ evdo_state_done (MMAtSerialPort *port, reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; break; default: - g_message ("ANYDATA: unknown *STATE (%d); assuming no service.", val); + mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val); /* fall through */ case 0: /* NO SERVICE */ case 1: /* ACQUISITION */ @@ -206,7 +207,7 @@ state_done (MMAtSerialPort *port, r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,.*", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { - g_warning ("AnyDATA(%s): *STATE parse regex creation failed.", __func__); + mm_warn ("ANYDATA: *STATE parse regex creation failed."); mm_callback_info_schedule (info); return; } @@ -235,7 +236,7 @@ state_done (MMAtSerialPort *port, reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; break; default: - g_warning ("ANYDATA: unknown *STATE (%d); assuming no service.", val); + mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val); /* fall through */ case 0: /* NO SERVICE */ break; @@ -272,6 +273,24 @@ query_registration_state (MMGenericCdma *cdma, /*****************************************************************************/ +static void +reset (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + + /* Ensure we have a usable port to use for the command */ + port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error); + if (port) + mm_at_serial_port_queue_command (port, "*RESET", 3, NULL, NULL); + + mm_callback_info_schedule (info); +} + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -333,6 +352,7 @@ static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; + modem_class->reset = reset; } static void diff --git a/plugins/mm-modem-huawei-cdma.c b/plugins/mm-modem-huawei-cdma.c index 7faa9f08..3aec470b 100644 --- a/plugins/mm-modem-huawei-cdma.c +++ b/plugins/mm-modem-huawei-cdma.c @@ -27,6 +27,7 @@ #include "mm-callback-info.h" #include "mm-serial-port.h" #include "mm-serial-parsers.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); @@ -79,7 +80,7 @@ parse_quality (const char *str, const char *detail) quality = strtol (str, NULL, 10); if (errno == 0) { quality = CLAMP (quality, 0, 100); - g_debug ("%s: %ld", detail, quality); + mm_dbg ("%s: %ld", detail, quality); return (gint) quality; } return -1; @@ -177,7 +178,7 @@ sysinfo_done (MMAtSerialPort *port, r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { - g_warning ("Huawei(%s): ^SYSINFO parse regex creation failed.", __func__); + mm_warn ("Huawei: ^SYSINFO parse regex creation failed."); goto done; } @@ -218,7 +219,7 @@ sysinfo_done (MMAtSerialPort *port, mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); } } else - g_warning ("Huawei(%s): failed to parse ^SYSINFO response.", __func__); + mm_warn ("Huawei: failed to parse ^SYSINFO response."); g_match_info_free (match_info); g_regex_unref (r); diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c index cde4b4a2..3fc9ae26 100644 --- a/plugins/mm-modem-huawei-gsm.c +++ b/plugins/mm-modem-huawei-gsm.c @@ -29,7 +29,7 @@ #include "mm-callback-info.h" #include "mm-at-serial-port.h" #include "mm-serial-parsers.h" -#include "mm-options.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class); @@ -367,6 +367,35 @@ get_band (MMModemGsmNetwork *modem, mm_at_serial_port_queue_command (port, "AT^SYSCFG?", 3, get_band_done, info); } +static MMModemGsmAccessTech +huawei_sysinfo_to_act (int huawei) +{ + switch (huawei) { + case 1: + return MM_MODEM_GSM_ACCESS_TECH_GSM; + case 2: + return MM_MODEM_GSM_ACCESS_TECH_GPRS; + case 3: + return MM_MODEM_GSM_ACCESS_TECH_EDGE; + case 4: + return MM_MODEM_GSM_ACCESS_TECH_UMTS; + case 5: + return MM_MODEM_GSM_ACCESS_TECH_HSDPA; + case 6: + return MM_MODEM_GSM_ACCESS_TECH_HSUPA; + case 7: + return MM_MODEM_GSM_ACCESS_TECH_HSPA; + case 9: + return MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS; + case 8: + /* TD-SCDMA */ + default: + break; + } + + return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; +} + static void get_act_request_done (MMAtSerialPort *port, GString *response, @@ -409,22 +438,8 @@ get_act_request_done (MMAtSerialPort *port, if (srv_stat != 0) { /* Valid service */ str = g_match_info_fetch (match_info, 7); - if (str && strlen (str)) { - if (str[0] == '1') - act = MM_MODEM_GSM_ACCESS_TECH_GSM; - else if (str[0] == '2') - act = MM_MODEM_GSM_ACCESS_TECH_GPRS; - else if (str[0] == '3') - act = MM_MODEM_GSM_ACCESS_TECH_EDGE; - else if (str[0] == '4') - act = MM_MODEM_GSM_ACCESS_TECH_UMTS; - else if (str[0] == '5') - act = MM_MODEM_GSM_ACCESS_TECH_HSDPA; - else if (str[0] == '6') - act = MM_MODEM_GSM_ACCESS_TECH_HSUPA; - else if (str[0] == '7') - act = MM_MODEM_GSM_ACCESS_TECH_HSPA; - } + if (str && strlen (str)) + act = huawei_sysinfo_to_act (atoi (str)); g_free (str); } @@ -519,7 +534,7 @@ send_huawei_cpin_done (MMAtSerialPort *port, else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN2)) num = 5; else { - g_debug ("%s: unhandled pin type '%s'", __func__, pin_type); + mm_dbg ("unhandled pin type '%s'", pin_type); info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type"); } @@ -561,7 +576,7 @@ get_unlock_retries (MMModemGsmCard *modem, char *command; MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - g_debug ("%s: pin type '%s'", __func__, pin_type); + mm_dbg ("pin type '%s'", pin_type); /* Ensure we have a usable port to use for the command */ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); @@ -627,40 +642,30 @@ handle_mode_change (MMAtSerialPort *port, MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; char *str; int a; - int b; str = g_match_info_fetch (match_info, 1); a = atoi (str); g_free (str); str = g_match_info_fetch (match_info, 2); - b = atoi (str); + act = huawei_sysinfo_to_act (atoi (str)); g_free (str); if (a == 3) { /* GSM/GPRS mode */ - if (b == 1) - act = MM_MODEM_GSM_ACCESS_TECH_GSM; - else if (b == 2) - act = MM_MODEM_GSM_ACCESS_TECH_GPRS; - else if (b == 3) - act = MM_MODEM_GSM_ACCESS_TECH_EDGE; + if (act > MM_MODEM_GSM_ACCESS_TECH_EDGE) + act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; } else if (a == 5) { /* WCDMA mode */ - if (b == 4) - act = MM_MODEM_GSM_ACCESS_TECH_UMTS; - else if (b == 5) - act = MM_MODEM_GSM_ACCESS_TECH_HSDPA; - else if (b == 6) - act = MM_MODEM_GSM_ACCESS_TECH_HSUPA; - else if (b == 7) - act = MM_MODEM_GSM_ACCESS_TECH_HSPA; + if (act < MM_MODEM_GSM_ACCESS_TECH_UMTS) + act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; } else if (a == 0) act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; else { - g_warning ("Couldn't parse mode change value: '%s'", str); + mm_warn ("Couldn't parse mode change value: '%s'", str); return; } - g_debug ("Access Technology: %d", act); + mm_dbg ("Access Technology: %d", act); + mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act); } @@ -674,10 +679,8 @@ handle_status_change (MMAtSerialPort *port, str = g_match_info_fetch (match_info, 1); if (sscanf (str, "%x,%x,%x,%x,%x,%x,%x", &n1, &n2, &n3, &n4, &n5, &n6, &n7)) { - if (mm_options_debug ()) { - g_debug ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n", - n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024); - } + mm_dbg ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n", + n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024); } g_free (str); } diff --git a/plugins/mm-modem-icera.c b/plugins/mm-modem-icera.c new file mode 100644 index 00000000..3f71c5b6 --- /dev/null +++ b/plugins/mm-modem-icera.c @@ -0,0 +1,794 @@ +/* -*- 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 option) 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) 2010 Red Hat, Inc. + */ + +/****************************************** + * Generic utilities for Icera-based modems + ******************************************/ + +#include <config.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> + +#include "mm-modem-icera.h" + +#include "mm-modem.h" +#include "mm-errors.h" +#include "mm-callback-info.h" +#include "mm-at-serial-port.h" +#include "mm-generic-gsm.h" +#include "mm-modem-helpers.h" +#include "mm-log.h" + +struct _MMModemIceraPrivate { + /* Pending connection attempt */ + MMCallbackInfo *connect_pending_data; + guint connect_pending_id; + + char *username; + char *password; + + MMModemGsmAccessTech last_act; +}; + +#define MM_MODEM_ICERA_GET_PRIVATE(m) (MM_MODEM_ICERA_GET_INTERFACE(m)->priv) + +static void +get_allowed_mode_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + gboolean parsed = FALSE; + + if (error) + info->error = g_error_copy (error); + else if (!g_str_has_prefix (response->str, "%IPSYS: ")) { + int a, b; + + if (sscanf (response->str + 8, "%d,%d", &a, &b)) { + MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY; + + switch (a) { + case 0: + mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY; + break; + case 1: + mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY; + break; + case 2: + mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED; + break; + case 3: + mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED; + break; + default: + break; + } + + mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL); + parsed = TRUE; + } + } + + if (!error && !parsed) + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Could not parse allowed mode results"); + + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_get_allowed_mode (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + mm_at_serial_port_queue_command (port, "%IPSYS?", 3, get_allowed_mode_done, info); +} + +static void +set_allowed_mode_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + info->error = g_error_copy (error); + + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_set_allowed_mode (MMModemIcera *self, + MMModemGsmAllowedMode mode, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + char *command; + int i; + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + switch (mode) { + case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY: + i = 0; + break; + case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY: + i = 1; + break; + case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED: + i = 2; + break; + case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED: + i = 3; + break; + case MM_MODEM_GSM_ALLOWED_MODE_ANY: + default: + i = 5; + break; + } + + command = g_strdup_printf ("%%IPSYS=%d", i); + mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info); + g_free (command); +} + +static MMModemGsmAccessTech +nwstate_to_act (const char *str) +{ + /* small 'g' means CS, big 'G' means PS */ + if (!strcmp (str, "2G-GPRS")) + return MM_MODEM_GSM_ACCESS_TECH_GPRS; + else if (!strcmp (str, "2G-EDGE")) + return MM_MODEM_GSM_ACCESS_TECH_EDGE; + else if (!strcmp (str, "3G")) + return MM_MODEM_GSM_ACCESS_TECH_UMTS; + else if (!strcmp (str, "3G-HSDPA")) + return MM_MODEM_GSM_ACCESS_TECH_HSDPA; + else if (!strcmp (str, "3G-HSUPA")) + return MM_MODEM_GSM_ACCESS_TECH_HSUPA; + else if (!strcmp (str, "3G-HSDPA-HSUPA")) + return MM_MODEM_GSM_ACCESS_TECH_HSPA; + + return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; +} + +static void +nwstate_changed (MMAtSerialPort *port, + GMatchInfo *info, + gpointer user_data) +{ + MMModemIcera *self = MM_MODEM_ICERA (user_data); + MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; + char *str; + int rssi = -1; + + str = g_match_info_fetch (info, 1); + if (str) { + rssi = atoi (str); + rssi = CLAMP (rssi, -1, 5); + g_free (str); + } + + str = g_match_info_fetch (info, 3); + if (str) { + act = nwstate_to_act (str); + g_free (str); + } + + MM_MODEM_ICERA_GET_PRIVATE (self)->last_act = act; + mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act); +} + +static void +pacsp_received (MMAtSerialPort *port, + GMatchInfo *info, + gpointer user_data) +{ + return; +} + +static void +get_nwstate_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + + info->error = mm_modem_check_removed (info->modem, error); + if (!info->error) { + MMModemIcera *self = MM_MODEM_ICERA (info->modem); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + /* The unsolicited message handler will already have run and + * removed the NWSTATE response, so we have to work around that. + */ + mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->last_act), NULL); + priv->last_act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; + } + + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_get_access_technology (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *port; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + mm_at_serial_port_queue_command (port, "%NWSTATE=1", 3, get_nwstate_done, info); +} + +/****************************************************************/ + +static void +disconnect_ipdpact_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + mm_callback_info_schedule ((MMCallbackInfo *) user_data); +} + +void +mm_modem_icera_do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *primary; + char *command; + + info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data); + + primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + command = g_strdup_printf ("%%IPDPACT=%d,0", cid); + mm_at_serial_port_queue_command (primary, command, 3, disconnect_ipdpact_done, info); + g_free (command); +} + +/*****************************************************************************/ + +static void +connect_pending_done (MMModemIcera *self) +{ + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + GError *error = NULL; + + if (priv->connect_pending_data) { + if (priv->connect_pending_data->error) { + error = priv->connect_pending_data->error; + priv->connect_pending_data->error = NULL; + } + + /* Complete the connect */ + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), error, priv->connect_pending_data); + priv->connect_pending_data = NULL; + } + + if (priv->connect_pending_id) { + g_source_remove (priv->connect_pending_id); + priv->connect_pending_id = 0; + } +} + +static void +icera_disconnect_done (MMModem *modem, + GError *error, + gpointer user_data) +{ + mm_info ("Modem signaled disconnection from the network"); +} + +static void +connection_enabled (MMAtSerialPort *port, + GMatchInfo *match_info, + gpointer user_data) +{ + MMModemIcera *self = MM_MODEM_ICERA (user_data); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + MMCallbackInfo *info = priv->connect_pending_data; + char *str; + int status, cid, tmp; + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); + if (cid < 0) + return; + + str = g_match_info_fetch (match_info, 1); + g_return_if_fail (str != NULL); + tmp = atoi (str); + g_free (str); + + /* Make sure the unsolicited message's CID matches the current CID */ + if (tmp != cid) + return; + + str = g_match_info_fetch (match_info, 2); + g_return_if_fail (str != NULL); + status = atoi (str); + g_free (str); + + switch (status) { + case 0: + /* Disconnected */ + if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_CONNECTED) + mm_modem_disconnect (MM_MODEM (self), icera_disconnect_done, NULL); + break; + case 1: + /* Connected */ + connect_pending_done (self); + break; + case 2: + /* Connecting */ + break; + case 3: + /* Call setup failure? */ + if (info) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Call setup failed"); + } + connect_pending_done (self); + break; + default: + mm_warn ("Unknown Icera connect status %d", status); + break; + } +} + +/****************************************************************/ + +static gint +_get_cid (MMModemIcera *self) +{ + gint cid; + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); + if (cid < 0) { + g_warn_if_fail (cid >= 0); + cid = 0; + } + return cid; +} + +static void +icera_call_control (MMModemIcera *self, + gboolean activate, + MMAtSerialResponseFn callback, + gpointer user_data) +{ + char *command; + MMAtSerialPort *primary; + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + command = g_strdup_printf ("%%IPDPACT=%d,%d", _get_cid (self), activate ? 1 : 0); + mm_at_serial_port_queue_command (primary, command, 3, callback, user_data); + g_free (command); +} + +static void +timeout_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + connect_pending_done (MM_MODEM_ICERA (user_data)); +} + +static gboolean +icera_connect_timed_out (gpointer data) +{ + MMModemIcera *self = MM_MODEM_ICERA (data); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + MMCallbackInfo *info = priv->connect_pending_data; + + priv->connect_pending_id = 0; + + if (info) { + info->error = g_error_new_literal (MM_SERIAL_ERROR, + MM_SERIAL_ERROR_RESPONSE_TIMEOUT, + "Connection timed out"); + } + + icera_call_control (self, FALSE, timeout_done, self); + return FALSE; +} + +static void +icera_enabled (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) { + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info); + } else { + MMModemIcera *self = MM_MODEM_ICERA (info->modem); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + g_warn_if_fail (priv->connect_pending_id == 0); + if (priv->connect_pending_id) + g_source_remove (priv->connect_pending_id); + + priv->connect_pending_data = info; + priv->connect_pending_id = g_timeout_add_seconds (30, icera_connect_timed_out, self); + } +} + +static void +old_context_clear_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + /* Activate the PDP context and start the data session */ + icera_call_control (MM_MODEM_ICERA (info->modem), TRUE, icera_enabled, info); +} + +static void +auth_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info); + else { + /* Ensure the PDP context is deactivated */ + icera_call_control (MM_MODEM_ICERA (info->modem), FALSE, old_context_clear_done, info); + } +} + +void +mm_modem_icera_do_connect (MMModemIcera *self, + const char *number, + MMModemFn callback, + gpointer user_data) +{ + MMModem *modem = MM_MODEM (self); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + MMCallbackInfo *info; + MMAtSerialPort *primary; + gint cid; + char *command; + + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); + + info = mm_callback_info_new (modem, callback, user_data); + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + cid = _get_cid (self); + + + /* Both user and password are required; otherwise firmware returns an error */ + if (!priv->username || !priv->password) + command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", cid); + else { + command = g_strdup_printf ("%%IPDPCFG=%d,0,1,\"%s\",\"%s\"", + cid, + priv->password ? priv->password : "", + priv->username ? priv->username : ""); + + } + + mm_at_serial_port_queue_command (primary, command, 3, auth_done, info); + g_free (command); +} + +/****************************************************************/ + + +static void +free_dns_array (gpointer data) +{ + g_array_free ((GArray *) data, TRUE); +} + +static void +ip4_config_invoke (MMCallbackInfo *info) +{ + MMModemIp4Fn callback = (MMModemIp4Fn) info->callback; + + callback (info->modem, + GPOINTER_TO_UINT (mm_callback_info_get_data (info, "ip4-address")), + (GArray *) mm_callback_info_get_data (info, "ip4-dns"), + info->error, info->user_data); +} + +#define IPDPADDR_TAG "%IPDPADDR: " + +static void +get_ip4_config_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + char **items, **iter; + GArray *dns_array; + int i; + guint32 tmp; + gint cid; + + if (error) { + info->error = g_error_copy (error); + goto out; + } else if (!g_str_has_prefix (response->str, IPDPADDR_TAG)) { + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Retrieving failed: invalid response."); + goto out; + } + + cid = _get_cid (MM_MODEM_ICERA (info->modem)); + dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2); + + /* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>[,<nbns1>,<nbns2>] */ + items = g_strsplit (response->str + strlen (IPDPADDR_TAG), ", ", 0); + + for (iter = items, i = 0; *iter; iter++, i++) { + if (i == 0) { /* CID */ + long int num; + + errno = 0; + num = strtol (*iter, NULL, 10); + if (errno != 0 || num < 0 || (gint) num != cid) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Unknown CID in IPDPADDR response (" + "got %d, expected %d)", (guint) num, cid); + break; + } + } else if (i == 1) { /* IP address */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + mm_callback_info_set_data (info, "ip4-address", GUINT_TO_POINTER (tmp), NULL); + } else if (i == 3) { /* DNS 1 */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + g_array_append_val (dns_array, tmp); + } else if (i == 4) { /* DNS 2 */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + g_array_append_val (dns_array, tmp); + } + } + + g_strfreev (items); + mm_callback_info_set_data (info, "ip4-dns", dns_array, free_dns_array); + + out: + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_get_ip4_config (MMModemIcera *self, + MMModemIp4Fn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *command; + MMAtSerialPort *primary; + + info = mm_callback_info_new_full (MM_MODEM (self), + ip4_config_invoke, + G_CALLBACK (callback), + user_data); + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + command = g_strdup_printf ("%%IPDPADDR=%d", _get_cid (self)); + mm_at_serial_port_queue_command (primary, command, 3, get_ip4_config_done, info); + g_free (command); +} + +/****************************************************************/ + +static const char * +get_string_property (GHashTable *properties, const char *name) +{ + GValue *value; + + value = (GValue *) g_hash_table_lookup (properties, name); + if (value && G_VALUE_HOLDS_STRING (value)) + return g_value_get_string (value); + return NULL; +} + +void +mm_modem_icera_simple_connect (MMModemIcera *self, GHashTable *properties) +{ + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + g_free (priv->username); + priv->username = g_strdup (get_string_property (properties, "username")); + g_free (priv->password); + priv->password = g_strdup (get_string_property (properties, "password")); +} + +/****************************************************************/ + +void +mm_modem_icera_register_unsolicted_handlers (MMModemIcera *self, + MMAtSerialPort *port) +{ + GRegex *regex; + + /* %NWSTATE: <rssi>,<mccmnc>,<tech>,<connected>,<regulation> */ + regex = g_regex_new ("\\r\\n%NWSTATE:\\s*(\\d+),(\\d+),([^,]*),([^,]*),(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, nwstate_changed, self, NULL); + g_regex_unref (regex); + + regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, pacsp_received, self, NULL); + g_regex_unref (regex); + + /* %IPDPACT: <cid>,<status>,0 */ + regex = g_regex_new ("\\r\\n%IPDPACT:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, connection_enabled, self, NULL); + g_regex_unref (regex); +} + +void +mm_modem_icera_change_unsolicited_messages (MMModemIcera *self, gboolean enabled) +{ + MMAtSerialPort *primary; + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + mm_at_serial_port_queue_command (primary, enabled ? "%NWSTATE=1" : "%NWSTATE=0", 3, NULL, NULL); +} + +/****************************************************************/ + +static void +is_icera_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + + info->error = mm_modem_check_removed (info->modem, error); + if (!info->error) + mm_callback_info_set_result (info, GUINT_TO_POINTER (TRUE), NULL); + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_is_icera (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *port; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + mm_at_serial_port_queue_command (port, "%IPSYS?", 5, is_icera_done, info); +} + +/****************************************************************/ + +void +mm_modem_icera_prepare (MMModemIcera *self) +{ + self->priv = g_malloc0 (sizeof (MMModemIceraPrivate)); +} + +void +mm_modem_icera_cleanup (MMModemIcera *self) +{ + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + /* Clear the pending connection if necessary */ + connect_pending_done (self); + + g_free (priv->username); + g_free (priv->password); + + memset (priv, 0, sizeof (MMModemIceraPrivate)); + g_free (priv); +} + +static void +mm_modem_icera_init (gpointer g_iface) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + initialized = TRUE; + } +} + +GType +mm_modem_icera_get_type (void) +{ + static GType icera_type = 0; + + if (!G_UNLIKELY (icera_type)) { + const GTypeInfo icera_info = { + sizeof (MMModemIcera), /* class_size */ + mm_modem_icera_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + icera_type = g_type_register_static (G_TYPE_INTERFACE, + "MMModemIcera", + &icera_info, 0); + + g_type_interface_add_prerequisite (icera_type, MM_TYPE_MODEM); + } + + return icera_type; +} + diff --git a/plugins/mm-modem-icera.h b/plugins/mm-modem-icera.h new file mode 100644 index 00000000..71258d2a --- /dev/null +++ b/plugins/mm-modem-icera.h @@ -0,0 +1,89 @@ +/* -*- 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 option) 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) 2010 Red Hat, Inc. + */ + +/****************************************** + * Generic utilities for Icera-based modems + ******************************************/ + +#ifndef MM_MODEM_ICERA_H +#define MM_MODEM_ICERA_H + +#include <glib-object.h> + +#include "mm-modem-gsm.h" +#include "mm-generic-gsm.h" + +#define MM_TYPE_MODEM_ICERA (mm_modem_icera_get_type ()) +#define MM_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_ICERA, MMModemIcera)) +#define MM_IS_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_ICERA)) +#define MM_MODEM_ICERA_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_ICERA, MMModemIcera)) + +typedef struct _MMModemIceraPrivate MMModemIceraPrivate; + +typedef struct _MMModemIcera MMModemIcera; + +struct _MMModemIcera { + GTypeInterface g_iface; + + MMModemIceraPrivate *priv; +}; + +GType mm_modem_icera_get_type (void); + +void mm_modem_icera_prepare (MMModemIcera *self); + +void mm_modem_icera_cleanup (MMModemIcera *self); + +void mm_modem_icera_get_allowed_mode (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data); + +void mm_modem_icera_set_allowed_mode (MMModemIcera *self, + MMModemGsmAllowedMode mode, + MMModemFn callback, + gpointer user_data); + +void mm_modem_icera_register_unsolicted_handlers (MMModemIcera *self, + MMAtSerialPort *port); + +void mm_modem_icera_change_unsolicited_messages (MMModemIcera *self, + gboolean enabled); + +void mm_modem_icera_get_access_technology (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data); + +void mm_modem_icera_is_icera (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data); + +void mm_modem_icera_do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data); + +void mm_modem_icera_simple_connect (MMModemIcera *self, GHashTable *properties); + +void mm_modem_icera_do_connect (MMModemIcera *self, + const char *number, + MMModemFn callback, + gpointer user_data); + +void mm_modem_icera_get_ip4_config (MMModemIcera *self, + MMModemIp4Fn callback, + gpointer user_data); + +#endif /* MM_MODEM_ICERA_H */ + diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index 53e98ba6..93034537 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Copyright (C) 2008 - 2010 Ericsson AB - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. * * Author: Per Hallsmark <per.hallsmark@ericsson.com> * Bjorn Runaker <bjorn.runaker@ericsson.com> @@ -31,6 +31,7 @@ #include "mm-modem-gsm-card.h" #include "mm-errors.h" #include "mm-callback-info.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class); @@ -410,7 +411,7 @@ mbm_emrdy_done (MMAtSerialPort *port, MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem); if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) - g_warning ("%s: timed out waiting for EMRDY response.", __func__); + mm_warn ("timed out waiting for EMRDY response."); else priv->have_emrdy = TRUE; @@ -510,6 +511,24 @@ do_disconnect (MMGenericGsm *gsm, } static void +reset (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + + /* Ensure we have a usable port to use for the command */ + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); + if (port) + mm_at_serial_port_queue_command (port, "*E2RESET", 3, NULL, NULL); + + mm_callback_info_schedule (info); +} + +static void factory_reset_done (MMAtSerialPort *port, GString *response, GError *error, @@ -614,16 +633,16 @@ mbm_e2nap_received (MMAtSerialPort *port, g_free (str); if (MBM_E2NAP_DISCONNECTED == state) { - g_debug ("%s: disconnected", __func__); + mm_dbg ("disconnected"); mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE); } else if (MBM_E2NAP_CONNECTED == state) { - g_debug ("%s: connected", __func__); + mm_dbg ("connected"); mbm_do_connect_done (MM_MODEM_MBM (user_data), TRUE); } else if (MBM_E2NAP_CONNECTING == state) - g_debug("%s: connecting", __func__); + mm_dbg ("connecting"); else { /* Should not happen */ - g_debug("%s: unhandled E2NAP state %d", __func__, state); + mm_dbg ("unhandled E2NAP state %d", state); mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE); } } @@ -793,7 +812,7 @@ send_epin_done (MMAtSerialPort *port, else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK2)) sscanf (response->str, "*EPIN: %*d, %*d, %*d, %d", &attempts_left); else { - g_debug ("%s: unhandled pin type '%s'", __func__, pin_type); + mm_dbg ("unhandled pin type '%s'", pin_type); info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type"); } @@ -820,7 +839,7 @@ mbm_get_unlock_retries (MMModemGsmCard *modem, char *command; MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - g_debug ("%s: pin type '%s'", __func__, pin_type); + mm_dbg ("pin type '%s'", pin_type); /* Ensure we have a usable port to use for the command */ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); @@ -940,6 +959,7 @@ modem_init (MMModem *modem_class) modem_class->grab_port = grab_port; modem_class->disable = disable; modem_class->connect = do_connect; + modem_class->reset = reset; modem_class->factory_reset = factory_reset; } diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c index 558260ec..c447c58f 100644 --- a/plugins/mm-modem-zte.c +++ b/plugins/mm-modem-zte.c @@ -24,11 +24,17 @@ #include "mm-errors.h" #include "mm-callback-info.h" #include "mm-modem-helpers.h" +#include "mm-modem-simple.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 *simple_class); G_DEFINE_TYPE_EXTENDED (MMModemZte, mm_modem_zte, MM_TYPE_GENERIC_GSM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)) + 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_ZTE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_ZTE, MMModemZtePrivate)) @@ -36,6 +42,7 @@ typedef struct { gboolean init_retried; guint32 cpms_tries; guint cpms_timeout; + gboolean is_icera; } MMModemZtePrivate; MMModem * @@ -149,9 +156,15 @@ get_allowed_mode (MMGenericGsm *gsm, MMModemUIntFn callback, gpointer user_data) { + MMModemZte *self = MM_MODEM_ZTE (gsm); MMCallbackInfo *info; MMAtSerialPort *port; + if (MM_MODEM_ZTE_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); port = mm_generic_gsm_get_best_at_port (gsm, &info->error); @@ -183,11 +196,17 @@ set_allowed_mode (MMGenericGsm *gsm, MMModemFn callback, gpointer user_data) { + MMModemZte *self = MM_MODEM_ZTE (gsm); MMCallbackInfo *info; MMAtSerialPort *port; char *command; int cm_mode = 0, pref_acq = 0; + if (MM_MODEM_ZTE_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); port = mm_generic_gsm_get_best_at_port (gsm, &info->error); @@ -248,16 +267,22 @@ get_act_request_done (MMAtSerialPort *port, } static void -get_access_technology (MMGenericGsm *modem, +get_access_technology (MMGenericGsm *gsm, MMModemUIntFn callback, gpointer user_data) { + MMModemZte *self = MM_MODEM_ZTE (gsm); MMAtSerialPort *port; MMCallbackInfo *info; - info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); + if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_access_technology (MM_MODEM_ICERA (self), callback, user_data); + return; + } - port = mm_generic_gsm_get_best_at_port (modem, &info->error); + info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (gsm, &info->error); if (!port) { mm_callback_info_schedule (info); return; @@ -266,6 +291,21 @@ get_access_technology (MMGenericGsm *modem, mm_at_serial_port_queue_command (port, "+ZPAS?", 3, get_act_request_done, info); } +static void +do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data) +{ + MMModemZte *self = MM_MODEM_ZTE (gsm); + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self); + + if (priv->is_icera) + mm_modem_icera_do_disconnect (gsm, cid, callback, user_data); + else + MM_GENERIC_GSM_CLASS (mm_modem_zte_parent_class)->do_disconnect (gsm, cid, callback, user_data); +} + /*****************************************************************************/ /* Modem class override functions */ /*****************************************************************************/ @@ -314,6 +354,10 @@ cpms_try_done (MMAtSerialPort *port, } } + /* Turn on unsolicited network state messages */ + if (priv->is_icera) + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (info->modem), TRUE); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } @@ -325,6 +369,8 @@ init_modem_done (MMAtSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + mm_at_serial_port_queue_command (port, "E0", 5, NULL, NULL); + /* Attempt to disable floods of "+ZUSIMR:2" unsolicited responses that * eventually fill up the device's buffers and make it crash. Normally * done during probing, but if the device has a PIN enabled it won't @@ -338,13 +384,33 @@ static void enable_flash_done (MMSerialPort *port, gpointer user_data); static void +icera_check_cb (MMModem *modem, + guint32 result, + GError *error, + gpointer user_data) +{ + if (!error) { + MMModemZte *self = MM_MODEM_ZTE (user_data); + MMModemZtePrivate *priv = MM_MODEM_ZTE_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); + } + } +} + +static void pre_init_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (info->modem); + MMModemZte *self = MM_MODEM_ZTE (info->modem); + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self); if (error) { /* Retry the init string one more time; the modem sometimes throws it away */ @@ -353,9 +419,10 @@ pre_init_done (MMAtSerialPort *port, priv->init_retried = TRUE; enable_flash_done (MM_SERIAL_PORT (port), NULL, user_data); } else - mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (self), error, info); } else { /* Finish the initialization */ + mm_modem_icera_is_icera (MM_MODEM_ICERA (self), icera_check_cb, self); mm_at_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info); } } @@ -387,21 +454,112 @@ do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data) mm_serial_port_flash (MM_SERIAL_PORT (primary), 100, FALSE, enable_flash_done, info); } +/*****************************************************************************/ + +typedef struct { + MMModem *modem; + MMModemFn callback; + gpointer user_data; +} DisableInfo; + +static void +disable_unsolicited_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) + +{ + MMModem *parent_modem_iface; + DisableInfo *info = user_data; + + parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem)); + parent_modem_iface->disable (info->modem, info->callback, info->user_data); + g_free (info); +} + static void disable (MMModem *modem, MMModemFn callback, gpointer user_data) { MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem); - MMModem *parent_modem_iface; + MMAtSerialPort *primary; + DisableInfo *info; priv->init_retried = FALSE; - /* Do the normal disable stuff */ - parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); - parent_modem_iface->disable (modem, callback, user_data); + info = g_malloc0 (sizeof (DisableInfo)); + info->callback = callback; + info->user_data = user_data; + info->modem = modem; + + 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); +} + +/*****************************************************************************/ + +static void +do_connect (MMModem *modem, + const char *number, + MMModemFn callback, + gpointer user_data) +{ + MMModem *parent_iface; + + if (MM_MODEM_ZTE_GET_PRIVATE (modem)->is_icera) + mm_modem_icera_do_connect (MM_MODEM_ICERA (modem), number, callback, user_data); + else { + parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); + parent_iface->connect (MM_MODEM (modem), number, callback, user_data); + } +} + +static void +get_ip4_config (MMModem *modem, + MMModemIp4Fn callback, + gpointer user_data) +{ + MMModem *parent_iface; + + if (MM_MODEM_ZTE_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 (MM_MODEM (modem), callback, user_data); + } +} + +/*****************************************************************************/ + +static void +simple_connect (MMModemSimple *simple, + GHashTable *properties, + MMModemFn callback, + gpointer user_data) +{ + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (simple); + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemSimple *parent_iface; + + if (priv->is_icera) + mm_modem_icera_simple_connect (MM_MODEM_ICERA (simple), properties); + + parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple)); + parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info); } +/*****************************************************************************/ + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -451,6 +609,9 @@ grab_port (MMModem *modem, regex = g_regex_new ("\\r\\n\\+ZEND\\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)); } return !!port; @@ -462,10 +623,24 @@ static void modem_init (MMModem *modem_class) { modem_class->disable = disable; + modem_class->connect = do_connect; + modem_class->get_ip4_config = get_ip4_config; modem_class->grab_port = grab_port; } static void +modem_icera_init (MMModemIcera *icera_class) +{ + mm_modem_icera_prepare (icera_class); +} + +static void +modem_simple_init (MMModemSimple *class) +{ + class->connect = simple_connect; +} + +static void mm_modem_zte_init (MMModemZte *self) { } @@ -478,6 +653,10 @@ dispose (GObject *object) if (priv->cpms_timeout) g_source_remove (priv->cpms_timeout); + + mm_modem_icera_cleanup (MM_MODEM_ICERA (self)); + + G_OBJECT_CLASS (mm_modem_zte_parent_class)->dispose (object); } static void @@ -491,6 +670,7 @@ mm_modem_zte_class_init (MMModemZteClass *klass) object_class->dispose = dispose; gsm_class->do_enable = do_enable; + gsm_class->do_disconnect = do_disconnect; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; gsm_class->get_access_technology = get_access_technology; diff --git a/plugins/mm-plugin-generic.c b/plugins/mm-plugin-generic.c index 9704ae84..a27704b4 100644 --- a/plugins/mm-plugin-generic.c +++ b/plugins/mm-plugin-generic.c @@ -31,6 +31,7 @@ #include "mm-generic-cdma.h" #include "mm-errors.h" #include "mm-serial-parsers.h" +#include "mm-log.h" G_DEFINE_TYPE (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE) @@ -127,10 +128,10 @@ grab_port (MMPluginBase *base, g_set_error (error, 0, 0, "Could not get port's sysfs file."); return NULL; } else { - g_message ("%s: (%s/%s) WARNING: missing udev 'device' file", - mm_plugin_get_name (MM_PLUGIN (base)), - subsys, - name); + mm_warn ("%s: (%s/%s) WARNING: missing udev 'device' file", + mm_plugin_get_name (MM_PLUGIN (base)), + subsys, + name); } } diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c index 090bb0d5..f1590ca3 100644 --- a/plugins/mm-plugin-huawei.c +++ b/plugins/mm-plugin-huawei.c @@ -27,6 +27,7 @@ #include "mm-modem-huawei-cdma.h" #include "mm-serial-parsers.h" #include "mm-at-serial-port.h" +#include "mm-log.h" G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE) @@ -240,10 +241,10 @@ supports_port (MMPluginBase *base, info->id = g_timeout_add_seconds (7, probe_secondary_timeout, task); if (!mm_serial_port_open (MM_SERIAL_PORT (info->serial), &error)) { - g_warning ("%s: (Huawei) %s: couldn't open serial port: (%d) %s", - __func__, name, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + 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; diff --git a/plugins/mm-plugin-mbm.c b/plugins/mm-plugin-mbm.c index dd64cc66..6684ff9a 100644 --- a/plugins/mm-plugin-mbm.c +++ b/plugins/mm-plugin-mbm.c @@ -84,7 +84,7 @@ supports_port (MMPluginBase *base, client = g_udev_client_new (sys); if (!client) { - g_warning ("mbm: could not get udev client."); + g_warn_if_fail (client != NULL); return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; } diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c index 97bbcc36..bb2ee176 100644 --- a/plugins/mm-plugin-zte.c +++ b/plugins/mm-plugin-zte.c @@ -11,7 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009 - 2010 Red Hat, Inc. */ #include <string.h> @@ -73,9 +73,6 @@ supports_port (MMPluginBase *base, /* Can't do anything with non-serial ports */ port = mm_plugin_base_supports_task_get_port (task); - if (strcmp (g_udev_device_get_subsystem (port), "tty")) - return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; - subsys = g_udev_device_get_subsystem (port); name = g_udev_device_get_name (port); @@ -85,6 +82,20 @@ supports_port (MMPluginBase *base, if (vendor != 0x19d2) return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + if (!strcmp (subsys, "net")) { + /* If we don't know the modem's type yet, defer grabbing the port + * until we know the type. + */ + if (!existing) + return MM_PLUGIN_SUPPORTS_PORT_DEFER; + + mm_plugin_base_supports_task_complete (task, 10); + return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; + } + + if (strcmp (subsys, "tty")) + return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) { level = get_level_for_capabilities (cached); if (level) { @@ -165,7 +176,7 @@ grab_port (MMPluginBase *base, return NULL; } } - } else if (get_level_for_capabilities (caps)) { + } else if (get_level_for_capabilities (caps) || (!strcmp (subsys, "net"))) { if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM) ptype = MM_PORT_TYPE_QCDM; |