~binli/ubuntu/trusty/modemmanager/lp1441095

« back to all changes in this revision

Viewing changes to plugins/sierra/mm-common-sierra.c

  • Committer: Bin Li
  • Date: 2015-09-25 10:04:57 UTC
  • Revision ID: bin.li@canonical.com-20150925100457-3wzddsnka6iyctwu
 * Support the MBIM for Dell. (LP: #1441095)

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 * Copyright (C) 2012 Lanedo GmbH
16
16
 */
17
17
 
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
 
18
21
#include "mm-common-sierra.h"
19
22
#include "mm-base-modem-at.h"
20
23
#include "mm-log.h"
24
27
static MMIfaceModem *iface_modem_parent;
25
28
 
26
29
/*****************************************************************************/
 
30
/* Custom init and port type hints */
 
31
 
 
32
#define TAG_SIERRA_APP_PORT       "sierra-app-port"
 
33
#define TAG_SIERRA_APP1_PPP_OK    "sierra-app1-ppp-ok"
 
34
 
 
35
gboolean
 
36
mm_common_sierra_grab_port (MMPlugin *self,
 
37
                            MMBaseModem *modem,
 
38
                            MMPortProbe *probe,
 
39
                            GError **error)
 
40
{
 
41
    MMAtPortFlag pflags = MM_AT_PORT_FLAG_NONE;
 
42
    MMPortType ptype;
 
43
 
 
44
    ptype = mm_port_probe_get_port_type (probe);
 
45
 
 
46
    /* Is it a GSM secondary port? */
 
47
    if (g_object_get_data (G_OBJECT (probe), TAG_SIERRA_APP_PORT)) {
 
48
        if (g_object_get_data (G_OBJECT (probe), TAG_SIERRA_APP1_PPP_OK))
 
49
            pflags = MM_AT_PORT_FLAG_PPP;
 
50
        else
 
51
            pflags = MM_AT_PORT_FLAG_SECONDARY;
 
52
    } else if (ptype == MM_PORT_TYPE_AT)
 
53
        pflags = MM_AT_PORT_FLAG_PRIMARY;
 
54
 
 
55
    return mm_base_modem_grab_port (modem,
 
56
                                    mm_port_probe_get_port_subsys (probe),
 
57
                                    mm_port_probe_get_port_name (probe),
 
58
                                    ptype,
 
59
                                    pflags,
 
60
                                    error);
 
61
}
 
62
 
 
63
gboolean
 
64
mm_common_sierra_port_probe_list_is_icera (GList *probes)
 
65
{
 
66
    GList *l;
 
67
 
 
68
    for (l = probes; l; l = g_list_next (l)) {
 
69
        /* Only assume the Icera probing check is valid IF the port is not
 
70
         * secondary. This will skip the stupid ports which reply OK to every
 
71
         * AT command, even the one we use to check for Icera support */
 
72
        if (mm_port_probe_is_icera (MM_PORT_PROBE (l->data)) &&
 
73
            !g_object_get_data (G_OBJECT (l->data), TAG_SIERRA_APP_PORT))
 
74
            return TRUE;
 
75
    }
 
76
 
 
77
    return FALSE;
 
78
}
 
79
 
 
80
typedef struct {
 
81
    MMPortProbe *probe;
 
82
    MMAtSerialPort *port;
 
83
    GCancellable *cancellable;
 
84
    GSimpleAsyncResult *result;
 
85
    guint retries;
 
86
} SierraCustomInitContext;
 
87
 
 
88
static void
 
89
sierra_custom_init_context_complete_and_free (SierraCustomInitContext *ctx)
 
90
{
 
91
    g_simple_async_result_complete_in_idle (ctx->result);
 
92
 
 
93
    if (ctx->cancellable)
 
94
        g_object_unref (ctx->cancellable);
 
95
    g_object_unref (ctx->port);
 
96
    g_object_unref (ctx->probe);
 
97
    g_object_unref (ctx->result);
 
98
    g_slice_free (SierraCustomInitContext, ctx);
 
99
}
 
100
 
 
101
gboolean
 
102
mm_common_sierra_custom_init_finish (MMPortProbe *probe,
 
103
                                     GAsyncResult *result,
 
104
                                     GError **error)
 
105
{
 
106
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
 
107
}
 
108
 
 
109
static void sierra_custom_init_step (SierraCustomInitContext *ctx);
 
110
 
 
111
static void
 
112
gcap_ready (MMAtSerialPort *port,
 
113
            GString *response,
 
114
            GError *error,
 
115
            SierraCustomInitContext *ctx)
 
116
{
 
117
    if (error) {
 
118
        /* If consumed all tries and the last error was a timeout, assume the
 
119
         * port is not AT */
 
120
        if (ctx->retries == 0 &&
 
121
            g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
 
122
            mm_port_probe_set_result_at (ctx->probe, FALSE);
 
123
        }
 
124
        /* If reported a hard parse error, this port is definitely not an AT
 
125
         * port, skip trying. */
 
126
        else if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_PARSE_FAILED)) {
 
127
            mm_port_probe_set_result_at (ctx->probe, FALSE);
 
128
            ctx->retries = 0;
 
129
        }
 
130
        /* Some Icera-based devices (eg, USB305) have an AT-style port that
 
131
         * replies to everything with ERROR, so tag as unsupported; sometimes
 
132
         * the real AT ports do this too, so let a retry tag the port as
 
133
         * supported if it responds correctly later. */
 
134
        else if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN)) {
 
135
            mm_port_probe_set_result_at (ctx->probe, FALSE);
 
136
        }
 
137
 
 
138
        /* Just retry... */
 
139
        sierra_custom_init_step (ctx);
 
140
        return;
 
141
    }
 
142
 
 
143
    /* A valid reply to ATI tells us this is an AT port already */
 
144
    mm_port_probe_set_result_at (ctx->probe, TRUE);
 
145
 
 
146
    /* Sierra APPx ports have limited AT command parsers that just reply with
 
147
     * "OK" to most commands.  These can sometimes be used for PPP while the
 
148
     * main port is used for status and control, but older modems tend to crash
 
149
     * or fail PPP.  So we whitelist modems that are known to allow PPP on the
 
150
     * secondary APP ports.
 
151
     */
 
152
    if (strstr (response->str, "APP1")) {
 
153
        g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP_PORT, GUINT_TO_POINTER (TRUE));
 
154
 
 
155
        /* PPP-on-APP1-port whitelist */
 
156
        if (strstr (response->str, "C885") ||
 
157
            strstr (response->str, "USB 306") ||
 
158
            strstr (response->str, "MC8790"))
 
159
            g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP1_PPP_OK, GUINT_TO_POINTER (TRUE));
 
160
 
 
161
        /* For debugging: let users figure out if their device supports PPP
 
162
         * on the APP1 port or not.
 
163
         */
 
164
        if (getenv ("MM_SIERRA_APP1_PPP_OK")) {
 
165
            mm_dbg ("Sierra: APP1 PPP OK '%s'", response->str);
 
166
            g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP1_PPP_OK, GUINT_TO_POINTER (TRUE));
 
167
        }
 
168
    } else if (strstr (response->str, "APP2") ||
 
169
               strstr (response->str, "APP3") ||
 
170
               strstr (response->str, "APP4")) {
 
171
        /* Additional APP ports don't support most AT commands, so they cannot
 
172
         * be used as the primary port.
 
173
         */
 
174
        g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP_PORT, GUINT_TO_POINTER (TRUE));
 
175
    }
 
176
 
 
177
    g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
 
178
    sierra_custom_init_context_complete_and_free (ctx);
 
179
}
 
180
 
 
181
static void
 
182
sierra_custom_init_step (SierraCustomInitContext *ctx)
 
183
{
 
184
    /* If cancelled, end */
 
185
    if (g_cancellable_is_cancelled (ctx->cancellable)) {
 
186
        mm_dbg ("(Sierra) no need to keep on running custom init in '%s'",
 
187
                mm_port_get_device (MM_PORT (ctx->port)));
 
188
        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
 
189
        sierra_custom_init_context_complete_and_free (ctx);
 
190
        return;
 
191
    }
 
192
 
 
193
    if (ctx->retries == 0) {
 
194
        mm_dbg ("(Sierra) Couldn't get port type hints from '%s'",
 
195
                mm_port_get_device (MM_PORT (ctx->port)));
 
196
        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
 
197
        sierra_custom_init_context_complete_and_free (ctx);
 
198
        return;
 
199
    }
 
200
 
 
201
    ctx->retries--;
 
202
    mm_at_serial_port_queue_command (
 
203
        ctx->port,
 
204
        "ATI",
 
205
        3,
 
206
        FALSE, /* raw */
 
207
        ctx->cancellable,
 
208
        (MMAtSerialResponseFn)gcap_ready,
 
209
        ctx);
 
210
}
 
211
 
 
212
void
 
213
mm_common_sierra_custom_init (MMPortProbe *probe,
 
214
                    MMAtSerialPort *port,
 
215
                    GCancellable *cancellable,
 
216
                    GAsyncReadyCallback callback,
 
217
                    gpointer user_data)
 
218
{
 
219
    SierraCustomInitContext *ctx;
 
220
 
 
221
    ctx = g_slice_new (SierraCustomInitContext);
 
222
    ctx->result = g_simple_async_result_new (G_OBJECT (probe),
 
223
                                             callback,
 
224
                                             user_data,
 
225
                                             mm_common_sierra_custom_init);
 
226
    ctx->probe = g_object_ref (probe);
 
227
    ctx->port = g_object_ref (port);
 
228
    ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 
229
    ctx->retries = 3;
 
230
 
 
231
    sierra_custom_init_step (ctx);
 
232
}
 
233
 
 
234
/*****************************************************************************/
27
235
/* Modem power up (Modem interface) */
28
236
 
29
237
gboolean