~binli/ubuntu/vivid/modemmanager/lp1441095

1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This program is free software; you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation; either version 2 of the License, or
6
 * (at your option) any later version.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 * GNU General Public License for more details:
12
 *
13
 * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
14
 */
15
16
#include <config.h>
17
18
#include <stdlib.h>
19
#include <stdio.h>
20
#include <string.h>
21
#include <unistd.h>
22
#include <ctype.h>
23
24
#include "mm-modem-helpers-mbim.h"
25
#include "mm-broadband-modem-mbim.h"
26
#include "mm-bearer-mbim.h"
27
#include "mm-sim-mbim.h"
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
28
#include "mm-sms-mbim.h"
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
29
30
#include "ModemManager.h"
31
#include "mm-log.h"
32
#include "mm-errors-types.h"
33
#include "mm-error-helpers.h"
34
#include "mm-modem-helpers.h"
35
#include "mm-bearer-list.h"
36
#include "mm-iface-modem.h"
37
#include "mm-iface-modem-3gpp.h"
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
38
#include "mm-iface-modem-messaging.h"
1.2.3 by Michael Biebl
Import upstream version 1.2.0
39
#include "mm-sms-part-3gpp.h"
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
40
41
static void iface_modem_init (MMIfaceModem *iface);
42
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
43
static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
44
45
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbim, mm_broadband_modem_mbim, MM_TYPE_BROADBAND_MODEM, 0,
46
                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
47
                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
48
                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init))
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
49
50
typedef enum {
51
    PROCESS_NOTIFICATION_FLAG_NONE                 = 0,
52
    PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY       = 1 << 0,
53
    PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES = 1 << 1,
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
54
    PROCESS_NOTIFICATION_FLAG_SMS_READ             = 1 << 2,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
55
} ProcessNotificationFlag;
56
57
struct _MMBroadbandModemMbimPrivate {
58
    /* Queried and cached capabilities */
59
    MbimCellularClass caps_cellular_class;
60
    MbimDataClass caps_data_class;
61
    MbimSmsCaps caps_sms;
62
    guint caps_max_sessions;
63
    gchar *caps_device_id;
64
    gchar *caps_firmware_info;
65
66
    /* Process unsolicited notifications */
67
    guint notification_id;
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
68
    ProcessNotificationFlag setup_flags;
69
    ProcessNotificationFlag enable_flags;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
70
71
    /* 3GPP registration helpers */
72
    gchar *current_operator_id;
73
    gchar *current_operator_name;
74
};
75
76
/*****************************************************************************/
77
78
static gboolean
79
peek_device (gpointer self,
80
             MbimDevice **o_device,
81
             GAsyncReadyCallback callback,
82
             gpointer user_data)
83
{
84
    MMMbimPort *port;
85
86
    port = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self));
87
    if (!port) {
88
        g_simple_async_report_error_in_idle (G_OBJECT (self),
89
                                             callback,
90
                                             user_data,
91
                                             MM_CORE_ERROR,
92
                                             MM_CORE_ERROR_FAILED,
93
                                             "Couldn't peek MBIM port");
94
        return FALSE;
95
    }
96
97
    *o_device = mm_mbim_port_peek_device (port);
98
    return TRUE;
99
}
100
101
/*****************************************************************************/
102
/* Current Capabilities loading (Modem interface) */
103
104
typedef struct {
105
    MMBroadbandModemMbim *self;
106
    GSimpleAsyncResult *result;
107
} LoadCapabilitiesContext;
108
109
static void
110
load_capabilities_context_complete_and_free (LoadCapabilitiesContext *ctx)
111
{
112
    g_simple_async_result_complete (ctx->result);
113
    g_object_unref (ctx->result);
114
    g_object_unref (ctx->self);
115
    g_slice_free (LoadCapabilitiesContext, ctx);
116
}
117
118
static MMModemCapability
119
modem_load_current_capabilities_finish (MMIfaceModem *self,
120
                                        GAsyncResult *res,
121
                                        GError **error)
122
{
123
    MMModemCapability caps;
124
    gchar *caps_str;
125
126
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
127
        return MM_MODEM_CAPABILITY_NONE;
128
129
    caps = ((MMModemCapability) GPOINTER_TO_UINT (
130
                g_simple_async_result_get_op_res_gpointer (
131
                    G_SIMPLE_ASYNC_RESULT (res))));
132
    caps_str = mm_modem_capability_build_string_from_mask (caps);
133
    mm_dbg ("loaded modem capabilities: %s", caps_str);
134
    g_free (caps_str);
135
    return caps;
136
}
137
138
static void
139
device_caps_query_ready (MbimDevice *device,
140
                         GAsyncResult *res,
141
                         LoadCapabilitiesContext *ctx)
142
{
143
    MMModemCapability mask;
144
    MbimMessage *response;
145
    GError *error = NULL;
146
147
    response = mbim_device_command_finish (device, res, &error);
148
    if (response &&
149
        mbim_message_command_done_get_result (response, &error) &&
150
        mbim_message_device_caps_response_parse (
151
            response,
152
            NULL, /* device_type */
153
            &ctx->self->priv->caps_cellular_class,
154
            NULL, /* voice_class */
155
            NULL, /* sim_class */
156
            &ctx->self->priv->caps_data_class,
157
            &ctx->self->priv->caps_sms,
158
            NULL, /* ctrl_caps */
159
            &ctx->self->priv->caps_max_sessions,
160
            NULL, /* custom_data_class */
161
            &ctx->self->priv->caps_device_id,
162
            &ctx->self->priv->caps_firmware_info,
163
            NULL, /* hardware_info */
164
            &error)) {
165
        /* Build mask of modem capabilities */
166
        mask = 0;
167
        if (ctx->self->priv->caps_cellular_class & MBIM_CELLULAR_CLASS_GSM)
168
            mask |= MM_MODEM_CAPABILITY_GSM_UMTS;
169
        if (ctx->self->priv->caps_cellular_class & MBIM_CELLULAR_CLASS_CDMA)
170
            mask |= MM_MODEM_CAPABILITY_CDMA_EVDO;
171
        if (ctx->self->priv->caps_data_class & MBIM_DATA_CLASS_LTE)
172
            mask |= MM_MODEM_CAPABILITY_LTE;
173
        g_simple_async_result_set_op_res_gpointer (ctx->result,
174
                                                   GUINT_TO_POINTER (mask),
175
                                                   NULL);
176
    } else
177
        g_simple_async_result_take_error (ctx->result, error);
178
179
    if (response)
180
        mbim_message_unref (response);
181
    load_capabilities_context_complete_and_free (ctx);
182
}
183
184
static void
185
modem_load_current_capabilities (MMIfaceModem *self,
186
                                 GAsyncReadyCallback callback,
187
                                 gpointer user_data)
188
{
189
    LoadCapabilitiesContext *ctx;
190
    MbimDevice *device;
191
    MbimMessage *message;
192
193
    if (!peek_device (self, &device, callback, user_data))
194
        return;
195
196
    ctx = g_slice_new (LoadCapabilitiesContext);
197
    ctx->self = g_object_ref (self);
198
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
199
                                             callback,
200
                                             user_data,
201
                                             modem_load_current_capabilities);
202
203
    mm_dbg ("loading current capabilities...");
204
    message = mbim_message_device_caps_query_new (NULL);
205
    mbim_device_command (device,
206
                         message,
207
                         10,
208
                         NULL,
209
                         (GAsyncReadyCallback)device_caps_query_ready,
210
                         ctx);
211
    mbim_message_unref (message);
212
}
213
214
/*****************************************************************************/
215
/* Manufacturer loading (Modem interface) */
216
217
static gchar *
218
modem_load_manufacturer_finish (MMIfaceModem *self,
219
                                GAsyncResult *res,
220
                                GError **error)
221
{
222
    return g_strdup (mm_base_modem_get_plugin (MM_BASE_MODEM (self)));
223
}
224
225
static void
226
modem_load_manufacturer (MMIfaceModem *self,
227
                         GAsyncReadyCallback callback,
228
                         gpointer user_data)
229
{
230
    GSimpleAsyncResult *result;
231
232
    result = g_simple_async_result_new (G_OBJECT (self),
233
                                        callback,
234
                                        user_data,
235
                                        modem_load_manufacturer);
236
    g_simple_async_result_complete_in_idle (result);
237
    g_object_unref (result);
238
}
239
240
/*****************************************************************************/
241
/* Model loading (Modem interface) */
242
243
static gchar *
244
modem_load_model_finish (MMIfaceModem *self,
245
                         GAsyncResult *res,
246
                         GError **error)
247
{
248
    return g_strdup_printf ("MBIM [%04X:%04X]",
249
                            (mm_base_modem_get_vendor_id (MM_BASE_MODEM (self)) & 0xFFFF),
250
                            (mm_base_modem_get_product_id (MM_BASE_MODEM (self)) & 0xFFFF));
251
252
}
253
254
static void
255
modem_load_model (MMIfaceModem *self,
256
                  GAsyncReadyCallback callback,
257
                  gpointer user_data)
258
{
259
    GSimpleAsyncResult *result;
260
261
    result = g_simple_async_result_new (G_OBJECT (self),
262
                                        callback,
263
                                        user_data,
1.2.3 by Michael Biebl
Import upstream version 1.2.0
264
                                        modem_load_model);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
265
    g_simple_async_result_complete_in_idle (result);
266
    g_object_unref (result);
267
}
268
269
/*****************************************************************************/
270
/* Revision loading (Modem interface) */
271
272
static gchar *
273
modem_load_revision_finish (MMIfaceModem *self,
274
                            GAsyncResult *res,
275
                            GError **error)
276
{
277
    if (MM_BROADBAND_MODEM_MBIM (self)->priv->caps_firmware_info)
278
        return g_strdup (MM_BROADBAND_MODEM_MBIM (self)->priv->caps_firmware_info);
279
280
    g_set_error (error,
281
                 MM_CORE_ERROR,
282
                 MM_CORE_ERROR_FAILED,
283
                 "Firmware revision information not given in device capabilities");
284
    return NULL;
285
}
286
287
static void
288
modem_load_revision (MMIfaceModem *self,
289
                     GAsyncReadyCallback callback,
290
                     gpointer user_data)
291
{
292
    GSimpleAsyncResult *result;
293
294
    /* Just complete */
295
    result = g_simple_async_result_new (G_OBJECT (self),
296
                                        callback,
297
                                        user_data,
298
                                        modem_load_revision);
299
    g_simple_async_result_complete_in_idle (result);
300
    g_object_unref (result);
301
}
302
303
/*****************************************************************************/
304
/* Equipment Identifier loading (Modem interface) */
305
306
static gchar *
307
modem_load_equipment_identifier_finish (MMIfaceModem *self,
308
                                        GAsyncResult *res,
309
                                        GError **error)
310
{
311
    if (MM_BROADBAND_MODEM_MBIM (self)->priv->caps_device_id)
312
        return g_strdup (MM_BROADBAND_MODEM_MBIM (self)->priv->caps_device_id);
313
314
    g_set_error (error,
315
                 MM_CORE_ERROR,
316
                 MM_CORE_ERROR_FAILED,
317
                 "Device ID not given in device capabilities");
318
    return NULL;
319
}
320
321
static void
322
modem_load_equipment_identifier (MMIfaceModem *self,
323
                                 GAsyncReadyCallback callback,
324
                                 gpointer user_data)
325
{
326
    GSimpleAsyncResult *result;
327
328
    /* Just complete */
329
    result = g_simple_async_result_new (G_OBJECT (self),
330
                                        callback,
331
                                        user_data,
332
                                        modem_load_equipment_identifier);
333
    g_simple_async_result_complete_in_idle (result);
334
    g_object_unref (result);
335
}
336
337
/*****************************************************************************/
338
/* Device identifier loading (Modem interface) */
339
340
static gchar *
341
modem_load_device_identifier_finish (MMIfaceModem *self,
342
                                     GAsyncResult *res,
343
                                     GError **error)
344
{
345
    gchar *device_identifier;
346
347
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
348
        return NULL;
349
350
    device_identifier = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
351
    return device_identifier;
352
}
353
354
static void
355
modem_load_device_identifier (MMIfaceModem *self,
356
                              GAsyncReadyCallback callback,
357
                              gpointer user_data)
358
{
359
    GSimpleAsyncResult *result;
360
    gchar *device_identifier;
361
362
    result = g_simple_async_result_new (G_OBJECT (self),
363
                                        callback,
364
                                        user_data,
365
                                        modem_load_device_identifier);
366
367
    /* Just use dummy ATI/ATI1 replies, all the other internal info should be
368
     * enough for uniqueness */
369
    device_identifier = mm_broadband_modem_create_device_identifier (MM_BROADBAND_MODEM (self), "", "");
370
    g_simple_async_result_set_op_res_gpointer (result,
371
                                               device_identifier,
372
                                               (GDestroyNotify)g_free);
373
    g_simple_async_result_complete_in_idle (result);
374
    g_object_unref (result);
375
}
376
377
/*****************************************************************************/
378
/* Supported modes loading (Modem interface) */
379
380
static GArray *
381
modem_load_supported_modes_finish (MMIfaceModem *self,
382
                                   GAsyncResult *res,
383
                                   GError **error)
384
{
385
    return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
386
}
387
388
static void
389
modem_load_supported_modes (MMIfaceModem *_self,
390
                            GAsyncReadyCallback callback,
391
                            gpointer user_data)
392
{
393
    MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
394
    GArray *combinations;
395
    MMModemModeCombination mode;
396
    GSimpleAsyncResult *result;
397
    MMModemMode all;
398
399
    /* Just complete */
400
    result = g_simple_async_result_new (G_OBJECT (self),
401
                                        callback,
402
                                        user_data,
403
                                        modem_load_supported_modes);
404
405
406
    if (self->priv->caps_data_class == 0) {
407
        g_simple_async_result_set_error (result,
408
                                         MM_CORE_ERROR,
409
                                         MM_CORE_ERROR_FAILED,
410
                                         "Data class not given in device capabilities");
411
        g_simple_async_result_complete_in_idle (result);
412
        g_object_unref (result);
413
        return;
414
    }
415
416
    all = 0;
417
418
    /* 3GPP... */
419
    if (self->priv->caps_data_class & (MBIM_DATA_CLASS_GPRS |
420
                                       MBIM_DATA_CLASS_EDGE))
421
        all |= MM_MODEM_MODE_2G;
422
    if (self->priv->caps_data_class & (MBIM_DATA_CLASS_UMTS |
423
                                       MBIM_DATA_CLASS_HSDPA |
424
                                       MBIM_DATA_CLASS_HSUPA))
425
        all |= MM_MODEM_MODE_3G;
426
    if (self->priv->caps_data_class & MBIM_DATA_CLASS_LTE)
427
        all |= MM_MODEM_MODE_4G;
428
429
    /* 3GPP2... */
430
    if (self->priv->caps_data_class & MBIM_DATA_CLASS_1XRTT)
431
        all |= MM_MODEM_MODE_2G;
432
    if (self->priv->caps_data_class & (MBIM_DATA_CLASS_1XEVDO |
433
                                       MBIM_DATA_CLASS_1XEVDO_REVA |
434
                                       MBIM_DATA_CLASS_1XEVDV |
435
                                       MBIM_DATA_CLASS_3XRTT |
436
                                       MBIM_DATA_CLASS_1XEVDO_REVB))
437
        all |= MM_MODEM_MODE_3G;
438
    if (self->priv->caps_data_class & MBIM_DATA_CLASS_UMB)
439
        all |= MM_MODEM_MODE_4G;
440
441
    /* Build a mask with all supported modes */
442
    combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
443
    mode.allowed = all;
444
    mode.preferred = MM_MODEM_MODE_NONE;
445
    g_array_append_val (combinations, mode);
446
447
    g_simple_async_result_set_op_res_gpointer (result, combinations, (GDestroyNotify) g_array_unref);
448
    g_simple_async_result_complete_in_idle (result);
449
    g_object_unref (result);
450
}
451
452
/*****************************************************************************/
453
/* Load supported IP families (Modem interface) */
454
455
static MMBearerIpFamily
456
modem_load_supported_ip_families_finish (MMIfaceModem *self,
457
                                         GAsyncResult *res,
458
                                         GError **error)
459
{
460
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
461
        return MM_BEARER_IP_FAMILY_NONE;
462
463
    return (MMBearerIpFamily) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
464
                                                    G_SIMPLE_ASYNC_RESULT (res)));
465
}
466
467
static void
468
modem_load_supported_ip_families (MMIfaceModem *self,
469
                                  GAsyncReadyCallback callback,
470
                                  gpointer user_data)
471
{
472
    GSimpleAsyncResult *result;
473
474
    result = g_simple_async_result_new (G_OBJECT (self),
475
                                        callback,
476
                                        user_data,
477
                                        modem_load_supported_ip_families);
478
479
    /* Assume IPv4 + IPv6 + IPv4v6 supported */
480
    g_simple_async_result_set_op_res_gpointer (
481
        result,
482
        GUINT_TO_POINTER (MM_BEARER_IP_FAMILY_IPV4 |
483
                          MM_BEARER_IP_FAMILY_IPV6 |
484
                          MM_BEARER_IP_FAMILY_IPV4V6),
485
        NULL);
486
    g_simple_async_result_complete_in_idle (result);
487
    g_object_unref (result);
488
}
489
490
/*****************************************************************************/
491
/* Unlock required loading (Modem interface) */
492
493
typedef struct {
494
    MMBroadbandModemMbim *self;
495
    GSimpleAsyncResult *result;
496
    guint n_ready_status_checks;
497
    MbimDevice *device;
498
} LoadUnlockRequiredContext;
499
500
static void
501
load_unlock_required_context_complete_and_free (LoadUnlockRequiredContext *ctx)
502
{
503
    g_simple_async_result_complete (ctx->result);
504
    g_object_unref (ctx->result);
505
    g_object_unref (ctx->device);
506
    g_object_unref (ctx->self);
507
    g_slice_free (LoadUnlockRequiredContext, ctx);
508
}
509
510
static MMModemLock
511
modem_load_unlock_required_finish (MMIfaceModem *self,
512
                                   GAsyncResult *res,
513
                                   GError **error)
514
{
515
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
516
        return MM_MODEM_LOCK_UNKNOWN;
517
518
    return (MMModemLock) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
519
}
520
521
static void
522
pin_query_ready (MbimDevice *device,
523
                 GAsyncResult *res,
524
                 LoadUnlockRequiredContext *ctx)
525
{
526
    MbimMessage *response;
527
    GError *error = NULL;
528
    MbimPinType pin_type;
529
    MbimPinState pin_state;
530
531
    response = mbim_device_command_finish (device, res, &error);
532
    if (response &&
533
        mbim_message_command_done_get_result (response, &error) &&
534
        mbim_message_pin_response_parse (
535
            response,
536
            &pin_type,
537
            &pin_state,
538
            NULL,
539
            &error)) {
540
        MMModemLock unlock_required;
541
542
        if (pin_state == MBIM_PIN_STATE_UNLOCKED)
543
            unlock_required = MM_MODEM_LOCK_NONE;
544
        else
545
            unlock_required = mm_modem_lock_from_mbim_pin_type (pin_type);
546
        g_simple_async_result_set_op_res_gpointer (ctx->result,
547
                                                   GUINT_TO_POINTER (unlock_required),
548
                                                   NULL);
549
    } else
550
        g_simple_async_result_take_error (ctx->result, error);
551
552
    if (response)
553
        mbim_message_unref (response);
554
    load_unlock_required_context_complete_and_free (ctx);
555
}
556
557
static gboolean wait_for_sim_ready (LoadUnlockRequiredContext *ctx);
558
559
static void
560
unlock_required_subscriber_ready_state_ready (MbimDevice *device,
561
                                              GAsyncResult *res,
562
                                              LoadUnlockRequiredContext *ctx)
563
{
564
    MbimMessage *response;
565
    GError *error = NULL;
566
    MbimSubscriberReadyState ready_state = MBIM_SUBSCRIBER_READY_STATE_NOT_INITIALIZED;
567
568
    response = mbim_device_command_finish (device, res, &error);
569
    if (response &&
570
        mbim_message_command_done_get_result (response, &error) &&
571
        mbim_message_subscriber_ready_status_response_parse (
572
            response,
573
            &ready_state,
574
            NULL, /* subscriber_id */
575
            NULL, /* sim_iccid */
576
            NULL, /* ready_info */
577
            NULL, /* telephone_numbers_count */
578
            NULL, /* telephone_numbers */
579
            &error)) {
580
        switch (ready_state) {
581
        case MBIM_SUBSCRIBER_READY_STATE_NOT_INITIALIZED:
582
        case MBIM_SUBSCRIBER_READY_STATE_INITIALIZED:
583
        case MBIM_SUBSCRIBER_READY_STATE_DEVICE_LOCKED:
584
            /* Don't set error */
585
            break;
586
        case MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED:
587
            /* This is an error, but we still want to retry.
588
             * The MC7710 may use this while the SIM is not ready yet. */
589
            break;
590
        case MBIM_SUBSCRIBER_READY_STATE_BAD_SIM:
591
            error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG);
592
            break;
593
        case MBIM_SUBSCRIBER_READY_STATE_FAILURE:
594
        case MBIM_SUBSCRIBER_READY_STATE_NOT_ACTIVATED:
595
        default:
596
            error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE);
597
            break;
598
        }
599
    }
600
601
    /* Fatal errors are reported right away */
602
    if (error) {
603
        g_simple_async_result_take_error (ctx->result, error);
604
        load_unlock_required_context_complete_and_free (ctx);
605
    }
606
    /* Need to retry? */
607
    else if (ready_state == MBIM_SUBSCRIBER_READY_STATE_NOT_INITIALIZED ||
608
             ready_state == MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED) {
609
        if (--ctx->n_ready_status_checks == 0) {
610
            /* All retries consumed, issue error */
611
            if (ready_state == MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED)
612
                g_simple_async_result_take_error (
613
                    ctx->result,
614
                    mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED));
615
            else
616
                g_simple_async_result_set_error (ctx->result,
617
                                                 MM_CORE_ERROR,
618
                                                 MM_CORE_ERROR_FAILED,
619
                                                 "Error waiting for SIM to get initialized");
620
            load_unlock_required_context_complete_and_free (ctx);
621
        } else {
622
            /* Retry */
623
            g_timeout_add_seconds (1, (GSourceFunc)wait_for_sim_ready, ctx);
624
        }
625
    }
626
    /* Initialized but locked? */
627
    else if (ready_state == MBIM_SUBSCRIBER_READY_STATE_DEVICE_LOCKED) {
628
        MbimMessage *message;
629
630
        /* Query which lock is to unlock */
631
        message = mbim_message_pin_query_new (NULL);
632
        mbim_device_command (device,
633
                             message,
634
                             10,
635
                             NULL,
636
                             (GAsyncReadyCallback)pin_query_ready,
637
                             ctx);
638
        mbim_message_unref (message);
639
    }
640
    /* Initialized but locked? */
641
    else if (ready_state == MBIM_SUBSCRIBER_READY_STATE_INITIALIZED) {
642
        g_simple_async_result_set_op_res_gpointer (ctx->result,
643
                                                   GUINT_TO_POINTER (MM_MODEM_LOCK_NONE),
644
                                                   NULL);
645
        load_unlock_required_context_complete_and_free (ctx);
646
    } else
647
        g_assert_not_reached ();
648
649
    if (response)
650
        mbim_message_unref (response);
651
}
652
653
static gboolean
654
wait_for_sim_ready (LoadUnlockRequiredContext *ctx)
655
{
656
    MbimMessage *message;
657
658
    message = mbim_message_subscriber_ready_status_query_new (NULL);
659
    mbim_device_command (ctx->device,
660
                         message,
661
                         10,
662
                         NULL,
663
                         (GAsyncReadyCallback)unlock_required_subscriber_ready_state_ready,
664
                         ctx);
665
    mbim_message_unref (message);
666
    return FALSE;
667
}
668
669
static void
670
modem_load_unlock_required (MMIfaceModem *self,
671
                            GAsyncReadyCallback callback,
672
                            gpointer user_data)
673
{
674
    LoadUnlockRequiredContext *ctx;
675
    MbimDevice *device;
676
677
    if (!peek_device (self, &device, callback, user_data))
678
        return;
679
680
    ctx = g_slice_new (LoadUnlockRequiredContext);
681
    ctx->self = g_object_ref (self);
682
    ctx->device = g_object_ref (device);
683
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
684
                                        callback,
685
                                        user_data,
686
                                        modem_load_unlock_required);
687
    ctx->n_ready_status_checks = 10;
688
689
    wait_for_sim_ready (ctx);
690
}
691
692
/*****************************************************************************/
693
/* Unlock retries loading (Modem interface) */
694
695
static MMUnlockRetries *
696
modem_load_unlock_retries_finish (MMIfaceModem *self,
697
                                  GAsyncResult *res,
698
                                  GError **error)
699
{
700
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
701
        return NULL;
702
703
    return MM_UNLOCK_RETRIES (g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
704
}
705
706
static void
707
pin_query_unlock_retries_ready (MbimDevice *device,
708
                                GAsyncResult *res,
709
                                GSimpleAsyncResult *simple)
710
{
711
    MbimMessage *response;
712
    GError *error = NULL;
713
    MbimPinType pin_type;
714
    guint32 remaining_attempts;
715
716
    response = mbim_device_command_finish (device, res, &error);
717
    if (response &&
718
        mbim_message_command_done_get_result (response, &error) &&
719
        mbim_message_pin_response_parse (
720
            response,
721
            &pin_type,
722
            NULL,
723
            &remaining_attempts,
724
            &error)) {
725
        MMUnlockRetries *retries;
726
727
        retries = mm_unlock_retries_new ();
728
        mm_unlock_retries_set (retries,
729
                               mm_modem_lock_from_mbim_pin_type (pin_type),
730
                               remaining_attempts);
731
        g_simple_async_result_set_op_res_gpointer (simple, retries, g_object_unref);
732
    } else
733
        g_simple_async_result_take_error (simple, error);
734
735
    if (response)
736
        mbim_message_unref (response);
737
    g_simple_async_result_complete (simple);
738
    g_object_unref (simple);
739
}
740
741
static void
742
modem_load_unlock_retries (MMIfaceModem *self,
743
                           GAsyncReadyCallback callback,
744
                           gpointer user_data)
745
{
746
    GSimpleAsyncResult *result;
747
    MbimDevice *device;
748
    MbimMessage *message;
749
750
    if (!peek_device (self, &device, callback, user_data))
751
        return;
752
753
    result = g_simple_async_result_new (G_OBJECT (self),
754
                                        callback,
755
                                        user_data,
756
                                        modem_load_unlock_retries);
757
758
    message = mbim_message_pin_query_new (NULL);
759
    mbim_device_command (device,
760
                         message,
761
                         10,
762
                         NULL,
763
                         (GAsyncReadyCallback)pin_query_unlock_retries_ready,
764
                         result);
765
    mbim_message_unref (message);
766
}
767
768
/*****************************************************************************/
769
/* Own numbers loading */
770
771
static GStrv
772
modem_load_own_numbers_finish (MMIfaceModem *self,
773
                               GAsyncResult *res,
774
                               GError **error)
775
{
776
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
777
        return NULL;
778
779
    return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
780
}
781
782
static void
783
own_numbers_subscriber_ready_state_ready (MbimDevice *device,
784
                                          GAsyncResult *res,
785
                                          GSimpleAsyncResult *simple)
786
{
787
    MbimMessage *response;
788
    GError *error = NULL;
789
    gchar **telephone_numbers;
790
791
    response = mbim_device_command_finish (device, res, &error);
792
    if (response &&
793
        mbim_message_command_done_get_result (response, &error) &&
794
        mbim_message_subscriber_ready_status_response_parse (
795
            response,
796
            NULL, /* ready_state */
797
            NULL, /* subscriber_id */
798
            NULL, /* sim_iccid */
799
            NULL, /* ready_info */
800
            NULL, /* telephone_numbers_count */
801
            &telephone_numbers,
802
            &error)) {
803
        g_simple_async_result_set_op_res_gpointer (simple, telephone_numbers, NULL);
804
    } else
805
        g_simple_async_result_take_error (simple, error);
806
807
    if (response)
808
        mbim_message_unref (response);
809
    g_simple_async_result_complete (simple);
810
    g_object_unref (simple);
811
}
812
813
static void
814
modem_load_own_numbers (MMIfaceModem *self,
815
                        GAsyncReadyCallback callback,
816
                        gpointer user_data)
817
{
818
    GSimpleAsyncResult *result;
819
    MbimDevice *device;
820
    MbimMessage *message;
821
822
    if (!peek_device (self, &device, callback, user_data))
823
        return;
824
825
    result = g_simple_async_result_new (G_OBJECT (self),
826
                                        callback,
827
                                        user_data,
828
                                        modem_load_own_numbers);
829
830
    message = mbim_message_subscriber_ready_status_query_new (NULL);
831
    mbim_device_command (device,
832
                         message,
833
                         10,
834
                         NULL,
835
                         (GAsyncReadyCallback)own_numbers_subscriber_ready_state_ready,
836
                         result);
837
    mbim_message_unref (message);
838
}
839
840
/*****************************************************************************/
841
/* Initial power state loading */
842
843
static MMModemPowerState
844
modem_load_power_state_finish (MMIfaceModem *self,
845
                               GAsyncResult *res,
846
                               GError **error)
847
{
848
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
849
        return MM_MODEM_POWER_STATE_UNKNOWN;
850
851
    return (MMModemPowerState) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
852
}
853
854
static void
855
radio_state_query_ready (MbimDevice *device,
856
                         GAsyncResult *res,
857
                         GSimpleAsyncResult *simple)
858
{
859
    MbimMessage *response;
860
    GError *error = NULL;
861
    MbimRadioSwitchState hardware_radio_state;
862
    MbimRadioSwitchState software_radio_state;
863
864
    response = mbim_device_command_finish (device, res, &error);
865
    if (response &&
866
        mbim_message_command_done_get_result (response, &error) &&
867
        mbim_message_radio_state_response_parse (
868
            response,
869
            &hardware_radio_state,
870
            &software_radio_state,
871
            &error)) {
872
        MMModemPowerState state;
873
874
        if (hardware_radio_state == MBIM_RADIO_SWITCH_STATE_OFF ||
875
            software_radio_state == MBIM_RADIO_SWITCH_STATE_OFF)
876
            state = MM_MODEM_POWER_STATE_LOW;
877
        else
878
            state = MM_MODEM_POWER_STATE_ON;
879
        g_simple_async_result_set_op_res_gpointer (simple,
880
                                                   GUINT_TO_POINTER (state),
881
                                                   NULL);
882
    } else
883
        g_simple_async_result_take_error (simple, error);
884
885
    if (response)
886
        mbim_message_unref (response);
887
    g_simple_async_result_complete (simple);
888
    g_object_unref (simple);
889
}
890
891
static void
892
modem_load_power_state (MMIfaceModem *self,
893
                        GAsyncReadyCallback callback,
894
                        gpointer user_data)
895
{
896
    GSimpleAsyncResult *result;
897
    MbimDevice *device;
898
    MbimMessage *message;
899
900
    if (!peek_device (self, &device, callback, user_data))
901
        return;
902
903
    result = g_simple_async_result_new (G_OBJECT (self),
904
                                        callback,
905
                                        user_data,
906
                                        modem_load_power_state);
907
908
    message = mbim_message_radio_state_query_new (NULL);
909
    mbim_device_command (device,
910
                         message,
911
                         10,
912
                         NULL,
913
                         (GAsyncReadyCallback)radio_state_query_ready,
914
                         result);
915
    mbim_message_unref (message);
916
}
917
918
/*****************************************************************************/
919
/* Power up/down (Modem interface) */
920
921
static gboolean
922
common_power_up_down_finish (MMIfaceModem *self,
923
                             GAsyncResult *res,
924
                             GError **error)
925
{
926
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
927
}
928
929
static void
930
radio_state_set_down_ready (MbimDevice *device,
931
                            GAsyncResult *res,
932
                            GSimpleAsyncResult *simple)
933
{
934
    MbimMessage *response;
935
    GError *error = NULL;
936
937
    response = mbim_device_command_finish (device, res, &error);
938
    if (response)
939
        mbim_message_command_done_get_result (response, &error);
940
941
    if (error)
942
        g_simple_async_result_take_error (simple, error);
943
    else
944
        g_simple_async_result_set_op_res_gboolean (simple, TRUE);
945
946
    if (response)
947
        mbim_message_unref (response);
948
    g_simple_async_result_complete (simple);
949
    g_object_unref (simple);
950
}
951
952
static void
953
radio_state_set_up_ready (MbimDevice *device,
954
                          GAsyncResult *res,
955
                          GSimpleAsyncResult *simple)
956
{
957
    MbimMessage *response;
958
    GError *error = NULL;
959
    MbimRadioSwitchState hardware_radio_state;
960
    MbimRadioSwitchState software_radio_state;
961
962
    response = mbim_device_command_finish (device, res, &error);
963
    if (response &&
964
        mbim_message_command_done_get_result (response, &error) &&
965
        mbim_message_radio_state_response_parse (
966
            response,
967
            &hardware_radio_state,
968
            &software_radio_state,
969
            &error)) {
970
        if (hardware_radio_state == MBIM_RADIO_SWITCH_STATE_OFF)
971
            error = g_error_new (MM_CORE_ERROR,
972
                                 MM_CORE_ERROR_FAILED,
973
                                 "Cannot power-up: hardware radio switch is OFF");
974
        else if (software_radio_state == MBIM_RADIO_SWITCH_STATE_OFF)
975
            g_warn_if_reached ();
976
    }
977
978
    if (error)
979
        g_simple_async_result_take_error (simple, error);
980
    else
981
        g_simple_async_result_set_op_res_gboolean (simple, TRUE);
982
983
    if (response)
984
        mbim_message_unref (response);
985
    g_simple_async_result_complete (simple);
986
    g_object_unref (simple);
987
}
988
989
static void
990
common_power_up_down (MMIfaceModem *self,
991
                      gboolean up,
992
                      GAsyncReadyCallback callback,
993
                      gpointer user_data)
994
{
995
    GSimpleAsyncResult *result;
996
    MbimDevice *device;
997
    MbimMessage *message;
998
    MbimRadioSwitchState state;
999
    GAsyncReadyCallback ready_cb;
1000
1001
    if (!peek_device (self, &device, callback, user_data))
1002
        return;
1003
1004
    result = g_simple_async_result_new (G_OBJECT (self),
1005
                                        callback,
1006
                                        user_data,
1007
                                        common_power_up_down);
1008
1009
    if (up) {
1010
        ready_cb = (GAsyncReadyCallback)radio_state_set_up_ready;
1011
        state = MBIM_RADIO_SWITCH_STATE_ON;
1012
    } else {
1013
        ready_cb = (GAsyncReadyCallback)radio_state_set_down_ready;
1014
        state = MBIM_RADIO_SWITCH_STATE_OFF;
1015
    }
1016
1017
    message = mbim_message_radio_state_set_new (state, NULL);
1018
    mbim_device_command (device,
1019
                         message,
1020
                         10,
1021
                         NULL,
1022
                         ready_cb,
1023
                         result);
1024
    mbim_message_unref (message);
1025
}
1026
1027
static void
1028
modem_power_down (MMIfaceModem *self,
1029
                  GAsyncReadyCallback callback,
1030
                  gpointer user_data)
1031
{
1032
    common_power_up_down (self, FALSE, callback, user_data);
1033
}
1034
1035
static void
1036
modem_power_up (MMIfaceModem *self,
1037
                GAsyncReadyCallback callback,
1038
                gpointer user_data)
1039
{
1040
    common_power_up_down (self, TRUE, callback, user_data);
1041
}
1042
1043
/*****************************************************************************/
1044
/* Create Bearer (Modem interface) */
1045
1046
static MMBearer *
1047
modem_create_bearer_finish (MMIfaceModem *self,
1048
                            GAsyncResult *res,
1049
                            GError **error)
1050
{
1051
    MMBearer *bearer;
1052
1053
    bearer = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
1054
    mm_dbg ("New bearer created at DBus path '%s'", mm_bearer_get_path (bearer));
1055
1056
    return g_object_ref (bearer);
1057
}
1058
1059
typedef struct {
1060
    guint32 session_id;
1061
    gboolean found;
1062
} FindSessionId;
1063
1064
static void
1065
bearer_list_session_id_foreach (MMBearer *bearer,
1066
                                gpointer user_data)
1067
{
1068
    FindSessionId *ctx = user_data;
1069
1070
    if (!ctx->found &&
1071
        MM_IS_BEARER_MBIM (bearer) &&
1072
        mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (bearer)) == ctx->session_id)
1073
        ctx->found = TRUE;
1074
}
1075
1076
static gint
1077
find_next_bearer_session_id (MMBroadbandModemMbim *self)
1078
{
1079
    MMBearerList *bearer_list;
1080
    guint i;
1081
1082
    g_object_get (self,
1083
                  MM_IFACE_MODEM_BEARER_LIST, &bearer_list,
1084
                  NULL);
1085
1086
    if (!bearer_list)
1087
        return 0;
1088
1089
    for (i = 0; i <= 255; i++) {
1090
        FindSessionId ctx;
1091
1092
        ctx.session_id = i;
1093
        ctx.found = FALSE;
1094
1095
        mm_bearer_list_foreach (bearer_list,
1096
                                bearer_list_session_id_foreach,
1097
                                &ctx);
1098
1099
        if (!ctx.found) {
1100
            g_object_unref (bearer_list);
1101
            return (gint)i;
1102
        }
1103
    }
1104
1105
    /* no valid session id found */
1106
    g_object_unref (bearer_list);
1107
    return -1;
1108
}
1109
1110
static void
1111
modem_create_bearer (MMIfaceModem *self,
1112
                     MMBearerProperties *properties,
1113
                     GAsyncReadyCallback callback,
1114
                     gpointer user_data)
1115
{
1116
    MMBearer *bearer;
1117
    GSimpleAsyncResult *result;
1118
    gint session_id;
1119
1120
    /* Set a new ref to the bearer object as result */
1121
    result = g_simple_async_result_new (G_OBJECT (self),
1122
                                        callback,
1123
                                        user_data,
1124
                                        modem_create_bearer);
1125
1126
    /* Find a new session ID */
1127
    session_id = find_next_bearer_session_id (MM_BROADBAND_MODEM_MBIM (self));
1128
    if (session_id < 0) {
1129
        g_simple_async_result_set_error (
1130
            result,
1131
            MM_CORE_ERROR,
1132
            MM_CORE_ERROR_FAILED,
1133
            "Not enough session IDs");
1134
        g_simple_async_result_complete_in_idle (result);
1135
        g_object_unref (result);
1136
        return;
1137
    }
1138
1139
    /* We just create a MMBearerMbim */
1140
    mm_dbg ("Creating MBIM bearer in MBIM modem");
1141
    bearer = mm_bearer_mbim_new (MM_BROADBAND_MODEM_MBIM (self),
1142
                                 properties,
1143
                                 (guint)session_id);
1144
1145
    g_simple_async_result_set_op_res_gpointer (result, bearer, g_object_unref);
1146
    g_simple_async_result_complete_in_idle (result);
1147
    g_object_unref (result);
1148
}
1149
1150
/*****************************************************************************/
1151
/* Create SIM (Modem interface) */
1152
1153
static MMSim *
1154
create_sim_finish (MMIfaceModem *self,
1155
                   GAsyncResult *res,
1156
                   GError **error)
1157
{
1158
    return mm_sim_mbim_new_finish (res, error);
1159
}
1160
1161
static void
1162
create_sim (MMIfaceModem *self,
1163
            GAsyncReadyCallback callback,
1164
            gpointer user_data)
1165
{
1166
    /* New MBIM SIM */
1167
    mm_sim_mbim_new (MM_BASE_MODEM (self),
1168
                    NULL, /* cancellable */
1169
                    callback,
1170
                    user_data);
1171
}
1172
1173
/*****************************************************************************/
1174
/* First enabling step */
1175
1176
static gboolean
1177
enabling_started_finish (MMBroadbandModem *self,
1178
                         GAsyncResult *res,
1179
                         GError **error)
1180
{
1181
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
1182
}
1183
1184
static void
1185
parent_enabling_started_ready (MMBroadbandModem *self,
1186
                               GAsyncResult *res,
1187
                               GSimpleAsyncResult *simple)
1188
{
1189
    GError *error = NULL;
1190
1191
    if (!MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbim_parent_class)->enabling_started_finish (
1192
            self,
1193
            res,
1194
            &error)) {
1195
        /* Don't treat this as fatal. Parent enabling may fail if it cannot grab a primary
1196
         * AT port, which isn't really an issue in MBIM-based modems */
1197
        mm_dbg ("Couldn't start parent enabling: %s", error->message);
1198
        g_error_free (error);
1199
    }
1200
1201
    g_simple_async_result_set_op_res_gboolean (simple, TRUE);
1202
    g_simple_async_result_complete (simple);
1203
    g_object_unref (simple);
1204
}
1205
1206
static void
1207
enabling_started (MMBroadbandModem *self,
1208
                  GAsyncReadyCallback callback,
1209
                  gpointer user_data)
1210
{
1211
    GSimpleAsyncResult *result;
1212
1213
    result = g_simple_async_result_new (G_OBJECT (self),
1214
                                        callback,
1215
                                        user_data,
1216
                                        enabling_started);
1217
    MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbim_parent_class)->enabling_started (
1218
        self,
1219
        (GAsyncReadyCallback)parent_enabling_started_ready,
1220
        result);
1221
}
1222
1223
/*****************************************************************************/
1224
/* First initialization step */
1225
1226
typedef struct {
1227
    MMBroadbandModem *self;
1228
    GSimpleAsyncResult *result;
1229
    MMMbimPort *mbim;
1230
} InitializationStartedContext;
1231
1232
static void
1233
initialization_started_context_complete_and_free (InitializationStartedContext *ctx)
1234
{
1235
    g_simple_async_result_complete_in_idle (ctx->result);
1236
    if (ctx->mbim)
1237
        g_object_unref (ctx->mbim);
1238
    g_object_unref (ctx->result);
1239
    g_object_unref (ctx->self);
1240
    g_slice_free (InitializationStartedContext, ctx);
1241
}
1242
1243
static gpointer
1244
initialization_started_finish (MMBroadbandModem *self,
1245
                               GAsyncResult *res,
1246
                               GError **error)
1247
{
1248
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1249
        return NULL;
1250
1251
    /* Just parent's pointer passed here */
1252
    return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
1253
}
1254
1255
static void
1256
parent_initialization_started_ready (MMBroadbandModem *self,
1257
                                     GAsyncResult *res,
1258
                                     InitializationStartedContext *ctx)
1259
{
1260
    gpointer parent_ctx;
1261
    GError *error = NULL;
1262
1263
    parent_ctx = MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbim_parent_class)->initialization_started_finish (
1264
        self,
1265
        res,
1266
        &error);
1267
    if (error) {
1268
        /* Don't treat this as fatal. Parent initialization may fail if it cannot grab a primary
1269
         * AT port, which isn't really an issue in MBIM-based modems */
1270
        mm_dbg ("Couldn't start parent initialization: %s", error->message);
1271
        g_error_free (error);
1272
    }
1273
1274
    g_simple_async_result_set_op_res_gpointer (ctx->result, parent_ctx, NULL);
1275
    initialization_started_context_complete_and_free (ctx);
1276
}
1277
1278
static void
1279
parent_initialization_started (InitializationStartedContext *ctx)
1280
{
1281
    MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbim_parent_class)->initialization_started (
1282
        ctx->self,
1283
        (GAsyncReadyCallback)parent_initialization_started_ready,
1284
        ctx);
1285
}
1286
1287
static void
1288
mbim_port_open_ready (MMMbimPort *mbim,
1289
                      GAsyncResult *res,
1290
                      InitializationStartedContext *ctx)
1291
{
1292
    GError *error = NULL;
1293
1294
    if (!mm_mbim_port_open_finish (mbim, res, &error)) {
1295
        g_simple_async_result_take_error (ctx->result, error);
1296
        initialization_started_context_complete_and_free (ctx);
1297
        return;
1298
    }
1299
1300
    /* Done we are, launch parent's callback */
1301
    parent_initialization_started (ctx);
1302
}
1303
1304
static void
1305
initialization_started (MMBroadbandModem *self,
1306
                        GAsyncReadyCallback callback,
1307
                        gpointer user_data)
1308
{
1309
    InitializationStartedContext *ctx;
1310
1311
    ctx = g_slice_new0 (InitializationStartedContext);
1312
    ctx->self = g_object_ref (self);
1313
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
1314
                                             callback,
1315
                                             user_data,
1316
                                             initialization_started);
1317
    ctx->mbim = mm_base_modem_get_port_mbim (MM_BASE_MODEM (self));
1318
1319
    /* This may happen if we unplug the modem unexpectedly */
1320
    if (!ctx->mbim) {
1321
        g_simple_async_result_set_error (ctx->result,
1322
                                         MM_CORE_ERROR,
1323
                                         MM_CORE_ERROR_FAILED,
1324
                                         "Cannot initialize: MBIM port went missing");
1325
        initialization_started_context_complete_and_free (ctx);
1326
        return;
1327
    }
1328
1329
    if (mm_mbim_port_is_open (ctx->mbim)) {
1330
        /* Nothing to be done, just launch parent's callback */
1331
        parent_initialization_started (ctx);
1332
        return;
1333
    }
1334
1335
    /* Now open our MBIM port */
1336
    mm_mbim_port_open (ctx->mbim,
1337
                       NULL,
1338
                       (GAsyncReadyCallback)mbim_port_open_ready,
1339
                       ctx);
1340
}
1341
1342
/*****************************************************************************/
1343
/* IMEI loading (3GPP interface) */
1344
1345
static gchar *
1346
modem_3gpp_load_imei_finish (MMIfaceModem3gpp *self,
1347
                             GAsyncResult *res,
1348
                             GError **error)
1349
{
1350
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1351
        return NULL;
1352
1353
    return g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
1354
}
1355
1356
static void
1357
modem_3gpp_load_imei (MMIfaceModem3gpp *_self,
1358
                      GAsyncReadyCallback callback,
1359
                      gpointer user_data)
1360
{
1361
    MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
1362
    GSimpleAsyncResult *result;
1363
1364
    result = g_simple_async_result_new (G_OBJECT (self),
1365
                                        callback,
1366
                                        user_data,
1367
                                        modem_3gpp_load_imei);
1368
1369
    if (self->priv->caps_device_id)
1370
        g_simple_async_result_set_op_res_gpointer (result,
1371
                                                   self->priv->caps_device_id,
1372
                                                   NULL);
1373
    else
1374
        g_simple_async_result_set_error (result,
1375
                                         MM_CORE_ERROR,
1376
                                         MM_CORE_ERROR_FAILED,
1377
                                         "Device doesn't report a valid IMEI");
1378
    g_simple_async_result_complete_in_idle (result);
1379
    g_object_unref (result);
1380
}
1381
1382
/*****************************************************************************/
1383
/* Facility locks status loading (3GPP interface) */
1384
1385
static MMModem3gppFacility
1386
modem_3gpp_load_enabled_facility_locks_finish (MMIfaceModem3gpp *self,
1387
                                               GAsyncResult *res,
1388
                                               GError **error)
1389
{
1390
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1391
        return MM_MODEM_3GPP_FACILITY_NONE;
1392
1393
    return ((MMModem3gppFacility) GPOINTER_TO_UINT (
1394
                g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
1395
}
1396
1397
static void
1398
pin_list_query_ready (MbimDevice *device,
1399
                      GAsyncResult *res,
1400
                      GSimpleAsyncResult *simple)
1401
{
1402
    MbimMessage *response;
1403
    GError *error = NULL;
1404
    MbimPinDesc *pin_desc_pin1;
1405
    MbimPinDesc *pin_desc_pin2;
1406
    MbimPinDesc *pin_desc_device_sim_pin;
1407
    MbimPinDesc *pin_desc_device_first_sim_pin;
1408
    MbimPinDesc *pin_desc_network_pin;
1409
    MbimPinDesc *pin_desc_network_subset_pin;
1410
    MbimPinDesc *pin_desc_service_provider_pin;
1411
    MbimPinDesc *pin_desc_corporate_pin;
1412
1413
    response = mbim_device_command_finish (device, res, &error);
1414
    if (response &&
1415
        mbim_message_command_done_get_result (response, &error) &&
1416
        mbim_message_pin_list_response_parse (
1417
            response,
1418
            &pin_desc_pin1,
1419
            &pin_desc_pin2,
1420
            &pin_desc_device_sim_pin,
1421
            &pin_desc_device_first_sim_pin,
1422
            &pin_desc_network_pin,
1423
            &pin_desc_network_subset_pin,
1424
            &pin_desc_service_provider_pin,
1425
            &pin_desc_corporate_pin,
1426
            NULL, /* pin_desc_subsidy_lock */
1427
            NULL, /* pin_desc_custom */
1428
            &error)) {
1429
        MMModem3gppFacility mask = MM_MODEM_3GPP_FACILITY_NONE;
1430
1431
        if (pin_desc_pin1->pin_mode == MBIM_PIN_MODE_ENABLED)
1432
            mask |= MM_MODEM_3GPP_FACILITY_SIM;
1433
        mbim_pin_desc_free (pin_desc_pin1);
1434
1435
        if (pin_desc_pin2->pin_mode == MBIM_PIN_MODE_ENABLED)
1436
            mask |= MM_MODEM_3GPP_FACILITY_FIXED_DIALING;
1437
        mbim_pin_desc_free (pin_desc_pin2);
1438
1439
        if (pin_desc_device_sim_pin->pin_mode == MBIM_PIN_MODE_ENABLED)
1440
            mask |= MM_MODEM_3GPP_FACILITY_PH_SIM;
1441
        mbim_pin_desc_free (pin_desc_device_sim_pin);
1442
1443
        if (pin_desc_device_first_sim_pin->pin_mode == MBIM_PIN_MODE_ENABLED)
1444
            mask |= MM_MODEM_3GPP_FACILITY_PH_FSIM;
1445
        mbim_pin_desc_free (pin_desc_device_first_sim_pin);
1446
1447
        if (pin_desc_network_pin->pin_mode == MBIM_PIN_MODE_ENABLED)
1448
            mask |= MM_MODEM_3GPP_FACILITY_NET_PERS;
1449
        mbim_pin_desc_free (pin_desc_network_pin);
1450
1451
        if (pin_desc_network_subset_pin->pin_mode == MBIM_PIN_MODE_ENABLED)
1452
            mask |= MM_MODEM_3GPP_FACILITY_NET_SUB_PERS;
1453
        mbim_pin_desc_free (pin_desc_network_subset_pin);
1454
1455
        if (pin_desc_service_provider_pin->pin_mode == MBIM_PIN_MODE_ENABLED)
1456
            mask |= MM_MODEM_3GPP_FACILITY_PROVIDER_PERS;
1457
        mbim_pin_desc_free (pin_desc_service_provider_pin);
1458
1459
        if (pin_desc_corporate_pin->pin_mode == MBIM_PIN_MODE_ENABLED)
1460
            mask |= MM_MODEM_3GPP_FACILITY_CORP_PERS;
1461
        mbim_pin_desc_free (pin_desc_corporate_pin);
1462
1463
        g_simple_async_result_set_op_res_gpointer (simple,
1464
                                                   GUINT_TO_POINTER (mask),
1465
                                                   NULL);
1466
    } else
1467
        g_simple_async_result_take_error (simple, error);
1468
1469
    if (response)
1470
        mbim_message_unref (response);
1471
    g_simple_async_result_complete (simple);
1472
    g_object_unref (simple);
1473
}
1474
1475
static void
1476
modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self,
1477
                                        GAsyncReadyCallback callback,
1478
                                        gpointer user_data)
1479
{
1480
    GSimpleAsyncResult *result;
1481
    MbimDevice *device;
1482
    MbimMessage *message;
1483
1484
    if (!peek_device (self, &device, callback, user_data))
1485
        return;
1486
1487
    result = g_simple_async_result_new (G_OBJECT (self),
1488
                                        callback,
1489
                                        user_data,
1.2.3 by Michael Biebl
Import upstream version 1.2.0
1490
                                        modem_3gpp_load_enabled_facility_locks);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1491
1492
    message = mbim_message_pin_list_query_new (NULL);
1493
    mbim_device_command (device,
1494
                         message,
1495
                         10,
1496
                         NULL,
1497
                         (GAsyncReadyCallback)pin_list_query_ready,
1498
                         result);
1499
    mbim_message_unref (message);
1500
}
1501
1502
/*****************************************************************************/
1503
/* Common unsolicited events setup and cleanup */
1504
1505
static void
1506
basic_connect_notification_signal_state (MMBroadbandModemMbim *self,
1507
                                         MbimMessage *notification)
1508
{
1509
    guint32 rssi;
1510
1511
    if (mbim_message_signal_state_notification_parse (
1512
            notification,
1513
            &rssi,
1514
            NULL, /* error_rate */
1515
            NULL, /* signal_strength_interval */
1516
            NULL, /* rssi_threshold */
1517
            NULL, /* error_rate_threshold */
1518
            NULL)) {
1519
        guint32 quality;
1520
1521
        /* Normalize the quality. 99 means unknown, we default it to 0 */
1522
        quality = CLAMP (rssi == 99 ? 0 : rssi, 0, 31) * 100 / 31;
1523
1524
        mm_dbg ("Signal state indication: %u --> %u%%", rssi, quality);
1525
        mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality);
1526
    }
1527
}
1528
1529
static void
1530
update_registration_info (MMBroadbandModemMbim *self,
1531
                          MbimRegisterState state,
1532
                          MbimDataClass available_data_classes,
1533
                          gchar *operator_id_take,
1534
                          gchar *operator_name_take)
1535
{
1536
    MMModem3gppRegistrationState reg_state;
1537
    MMModemAccessTechnology act;
1538
1539
    reg_state = mm_modem_3gpp_registration_state_from_mbim_register_state (state);
1540
    act = mm_modem_access_technology_from_mbim_data_class (available_data_classes);
1541
1542
    if (reg_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1543
        reg_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1544
        if (self->priv->current_operator_id &&
1545
            g_str_equal (self->priv->current_operator_id, operator_id_take)) {
1546
            g_free (operator_id_take);
1547
        } else {
1548
            g_free (self->priv->current_operator_id);
1549
            self->priv->current_operator_id = operator_id_take;
1550
        }
1551
1552
        if (self->priv->current_operator_name &&
1553
            g_str_equal (self->priv->current_operator_name, operator_name_take)) {
1554
            g_free (operator_name_take);
1555
        } else {
1556
            g_free (self->priv->current_operator_name);
1557
            self->priv->current_operator_name = operator_name_take;
1558
        }
1559
    } else {
1560
        if (self->priv->current_operator_id) {
1561
            g_free (self->priv->current_operator_id);
1562
            self->priv->current_operator_id = 0;
1563
        }
1564
        if (self->priv->current_operator_name) {
1565
            g_free (self->priv->current_operator_name);
1566
            self->priv->current_operator_name = 0;
1567
        }
1568
        g_free (operator_id_take);
1569
        g_free (operator_name_take);
1570
    }
1571
1572
    mm_iface_modem_3gpp_update_ps_registration_state (
1573
        MM_IFACE_MODEM_3GPP (self),
1574
        reg_state);
1575
1576
    mm_iface_modem_3gpp_update_access_technologies (
1577
        MM_IFACE_MODEM_3GPP (self),
1578
        act);
1579
}
1580
1581
static void
1582
basic_connect_notification_register_state (MMBroadbandModemMbim *self,
1583
                                           MbimMessage *notification)
1584
{
1585
    MbimRegisterState register_state;
1586
    MbimDataClass available_data_classes;
1587
    gchar *provider_id;
1588
    gchar *provider_name;
1589
1590
    if (mbim_message_register_state_notification_parse (
1591
            notification,
1592
            NULL, /* nw_error */
1593
            &register_state,
1594
            NULL, /* register_mode */
1595
            &available_data_classes,
1596
            NULL, /* current_cellular_class */
1597
            &provider_id,
1598
            &provider_name,
1599
            NULL, /* roaming_text */
1600
            NULL, /* registration_flag */
1601
            NULL)) {
1602
        update_registration_info (self,
1603
                                  register_state,
1604
                                  available_data_classes,
1605
                                  provider_id,
1606
                                  provider_name);
1607
    }
1608
}
1609
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1610
static void add_sms_part (MMBroadbandModemMbim *self,
1611
                          const MbimSmsPduReadRecord *pdu);
1612
1613
static void
1614
sms_notification_read_sms (MMBroadbandModemMbim *self,
1615
                           MbimMessage *notification)
1616
{
1617
    MbimSmsFormat format;
1618
    guint32 messages_count;
1619
    MbimSmsPduReadRecord **pdu_messages;
1620
    guint i;
1621
1622
    if (!mbim_message_sms_read_notification_parse (
1623
            notification,
1624
            &format,
1625
            &messages_count,
1626
            &pdu_messages,
1627
            NULL, /* cdma_messages */
1628
            NULL) ||
1629
        /* Only PDUs */
1630
        format != MBIM_SMS_FORMAT_PDU) {
1631
        return;
1632
    }
1633
1634
    for (i = 0; i < messages_count; i++)
1635
        add_sms_part (self, pdu_messages[i]);
1636
1637
    mbim_sms_pdu_read_record_array_free (pdu_messages);
1638
}
1639
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1640
static void
1641
basic_connect_notification (MMBroadbandModemMbim *self,
1642
                            MbimMessage *notification)
1643
{
1644
    switch (mbim_message_indicate_status_get_cid (notification)) {
1645
    case MBIM_CID_BASIC_CONNECT_SIGNAL_STATE:
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1646
        if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY)
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1647
            basic_connect_notification_signal_state (self, notification);
1648
        break;
1649
    case MBIM_CID_BASIC_CONNECT_REGISTER_STATE:
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1650
        if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES)
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1651
            basic_connect_notification_register_state (self, notification);
1652
        break;
1653
    default:
1654
        /* Ignore */
1655
        break;
1656
    }
1657
}
1658
1659
static void
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1660
alert_sms_read_query_ready (MbimDevice *device,
1661
                            GAsyncResult *res,
1662
                            MMBroadbandModemMbim *self)
1663
{
1664
    MbimMessage *response;
1665
    GError *error = NULL;
1666
    guint32 messages_count;
1667
    MbimSmsPduReadRecord **pdu_messages;
1668
1669
    response = mbim_device_command_finish (device, res, &error);
1670
    if (response &&
1671
        mbim_message_command_done_get_result (response, &error) &&
1672
        mbim_message_sms_read_response_parse (
1673
            response,
1674
            NULL,
1675
            &messages_count,
1676
            &pdu_messages,
1677
            NULL, /* cdma_messages */
1678
            &error)) {
1679
        guint i;
1680
1681
        for (i = 0; i < messages_count; i++)
1682
            add_sms_part (self, pdu_messages[i]);
1683
        mbim_sms_pdu_read_record_array_free (pdu_messages);
1684
    }
1685
1686
    if (error) {
1687
        mm_dbg ("Flash message reading failed: %s", error->message);
1688
        g_error_free (error);
1689
    }
1690
1691
    if (response)
1692
        mbim_message_unref (response);
1693
1694
    g_object_unref (self);
1695
}
1696
1697
static void
1698
sms_notification_read_alert_sms (MMBroadbandModemMbim *self,
1699
                                 guint32 index)
1700
{
1701
    MMMbimPort *port;
1702
    MbimDevice *device;
1703
    MbimMessage *message;
1704
1705
    port = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self));
1706
    if (!port)
1707
        return;
1708
    device = mm_mbim_port_peek_device (port);
1709
    if (!device)
1710
        return;
1711
1712
    mm_dbg ("Reading flash SMS at index '%u'", index);
1713
    message = mbim_message_sms_read_query_new (MBIM_SMS_FORMAT_PDU,
1714
                                               MBIM_SMS_FLAG_INDEX,
1715
                                               index,
1716
                                               NULL);
1717
    mbim_device_command (device,
1718
                         message,
1719
                         10,
1720
                         NULL,
1721
                         (GAsyncReadyCallback)alert_sms_read_query_ready,
1722
                         g_object_ref (self));
1723
    mbim_message_unref (message);
1724
}
1725
1726
static void
1727
sms_notification (MMBroadbandModemMbim *self,
1728
                  MbimMessage *notification)
1729
{
1730
    switch (mbim_message_indicate_status_get_cid (notification)) {
1731
    case MBIM_CID_SMS_READ:
1732
        if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ)
1733
            sms_notification_read_sms (self, notification);
1734
        break;
1735
1736
    case MBIM_CID_SMS_MESSAGE_STORE_STATUS: {
1737
        MbimSmsStatusFlag flag;
1738
        guint32 index;
1739
1740
        /* New flash/alert message? */
1741
        if (self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ &&
1742
            mbim_message_sms_message_store_status_notification_parse (
1743
                notification,
1744
                &flag,
1745
                &index,
1746
                NULL)) {
1747
            mm_dbg ("Received flash message: '%s'", mbim_sms_status_flag_get_string (flag));
1748
            if (flag == MBIM_SMS_STATUS_FLAG_NEW_MESSAGE)
1749
                sms_notification_read_alert_sms (self, index);
1750
        }
1751
        break;
1752
    }
1753
1754
    default:
1755
        /* Ignore */
1756
        break;
1757
    }
1758
}
1759
1760
static void
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1761
device_notification_cb (MbimDevice *device,
1762
                        MbimMessage *notification,
1763
                        MMBroadbandModemMbim *self)
1764
{
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1765
    MbimService service;
1766
1767
    service = mbim_message_indicate_status_get_service (notification);
1768
    mm_dbg ("Received notification (service '%s', command '%s')",
1769
            mbim_service_get_string (service),
1770
            mbim_cid_get_printable (service,
1771
                                    mbim_message_indicate_status_get_cid (notification)));
1772
1773
    switch (service) {
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1774
    case MBIM_SERVICE_BASIC_CONNECT:
1775
        basic_connect_notification (self, notification);
1776
        break;
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1777
    case MBIM_SERVICE_SMS:
1778
        sms_notification (self, notification);
1779
        break;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1780
    default:
1781
        /* Ignore */
1782
        break;
1783
    }
1784
}
1785
1786
static gboolean
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1787
common_setup_cleanup_unsolicited_events_finish (MMBroadbandModemMbim *self,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1788
                                                GAsyncResult *res,
1789
                                                GError **error)
1790
{
1791
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
1792
}
1793
1794
static void
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1795
common_setup_cleanup_unsolicited_events (MMBroadbandModemMbim *self,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1796
                                         gboolean setup,
1797
                                         GAsyncReadyCallback callback,
1798
                                         gpointer user_data)
1799
{
1800
    MbimDevice *device;
1801
    GSimpleAsyncResult *result;
1802
1803
    if (!peek_device (self, &device, callback, user_data))
1804
        return;
1805
1806
    result = g_simple_async_result_new (G_OBJECT (self),
1807
                                        callback,
1808
                                        user_data,
1809
                                        common_setup_cleanup_unsolicited_events);
1810
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1811
    mm_dbg ("Supported notifications: signal (%s), registration (%s), sms (%s)",
1812
            self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no",
1813
            self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no",
1814
            self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no");
1815
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1816
    if (setup) {
1817
        /* Don't re-enable it if already there */
1818
        if (!self->priv->notification_id)
1819
            self->priv->notification_id =
1820
                g_signal_connect (device,
1821
                                  MBIM_DEVICE_SIGNAL_INDICATE_STATUS,
1822
                                  G_CALLBACK (device_notification_cb),
1823
                                  self);
1824
    } else {
1825
        /* Don't remove the signal if there are still listeners interested */
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1826
        if (self->priv->setup_flags == PROCESS_NOTIFICATION_FLAG_NONE &&
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1827
            self->priv->notification_id &&
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1828
            g_signal_handler_is_connected (device, self->priv->notification_id)) {
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1829
            g_signal_handler_disconnect (device, self->priv->notification_id);
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1830
            self->priv->notification_id = 0;
1831
        }
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1832
    }
1833
1834
    g_simple_async_result_complete_in_idle (result);
1835
    g_object_unref (result);
1836
}
1837
1838
/*****************************************************************************/
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1839
/* Setup/cleanup unsolicited events (3GPP interface) */
1840
1841
static gboolean
1842
common_setup_cleanup_unsolicited_events_3gpp_finish (MMIfaceModem3gpp *self,
1843
                                                     GAsyncResult *res,
1844
                                                     GError **error)
1845
{
1846
    return common_setup_cleanup_unsolicited_events_finish (MM_BROADBAND_MODEM_MBIM (self), res, error);
1847
}
1848
1849
static void
1850
cleanup_unsolicited_events_3gpp (MMIfaceModem3gpp *self,
1851
                                 GAsyncReadyCallback callback,
1852
                                 gpointer user_data)
1853
{
1854
    MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
1855
    common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), FALSE, callback, user_data);
1856
}
1857
1858
static void
1859
setup_unsolicited_events_3gpp (MMIfaceModem3gpp *self,
1860
                               GAsyncReadyCallback callback,
1861
                               gpointer user_data)
1862
{
1863
    MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
1864
    common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), TRUE, callback, user_data);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1865
}
1866
1867
/*****************************************************************************/
1868
/* Cleanup/Setup unsolicited registration events */
1869
1870
static void
1871
cleanup_unsolicited_registration_events (MMIfaceModem3gpp *self,
1872
                                         GAsyncReadyCallback callback,
1873
                                         gpointer user_data)
1874
{
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1875
    MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES;
1876
    common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), FALSE, callback, user_data);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1877
}
1878
1879
static void
1880
setup_unsolicited_registration_events (MMIfaceModem3gpp *self,
1881
                                       GAsyncReadyCallback callback,
1882
                                       gpointer user_data)
1883
{
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1884
    MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES;
1885
    common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), TRUE, callback, user_data);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1886
}
1887
1888
/*****************************************************************************/
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1889
/* Enable/disable unsolicited events (common) */
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1890
1891
static gboolean
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1892
common_enable_disable_unsolicited_events_finish (MMBroadbandModemMbim *self,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1893
                                                 GAsyncResult *res,
1894
                                                 GError **error)
1895
{
1896
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
1897
}
1898
1899
static void
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1900
subscriber_list_set_ready_cb (MbimDevice *device,
1901
                              GAsyncResult *res,
1902
                              GSimpleAsyncResult *simple)
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1903
{
1904
    MbimMessage *response;
1905
    GError *error = NULL;
1906
1907
    response = mbim_device_command_finish (device, res, &error);
1908
    if (response)
1909
        mbim_message_command_done_get_result (response, &error);
1910
1911
    if (error)
1912
        g_simple_async_result_take_error (simple, error);
1913
    else
1914
        g_simple_async_result_set_op_res_gboolean (simple, TRUE);
1915
1916
    if (response)
1917
        mbim_message_unref (response);
1918
    g_simple_async_result_complete (simple);
1919
    g_object_unref (simple);
1920
}
1921
1922
static void
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1923
common_enable_disable_unsolicited_events (MMBroadbandModemMbim *self,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1924
                                          GAsyncReadyCallback callback,
1925
                                          gpointer user_data)
1926
{
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1927
    MbimMessage *request;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1928
    MbimDevice *device;
1929
    GSimpleAsyncResult *result;
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1930
    MbimEventEntry **entries;
1931
    guint n_entries = 0;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1932
1933
    if (!peek_device (self, &device, callback, user_data))
1934
        return;
1935
1936
    result = g_simple_async_result_new (G_OBJECT (self),
1937
                                        callback,
1938
                                        user_data,
1939
                                        common_enable_disable_unsolicited_events);
1940
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1941
    mm_dbg ("Enabled notifications: signal (%s), registration (%s), sms (%s)",
1942
            self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no",
1943
            self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no",
1944
            self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no");
1945
1946
    entries = g_new0 (MbimEventEntry *, 3);
1947
1948
    /* Basic connect service */
1949
    if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ||
1950
        self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES) {
1951
        entries[n_entries] = g_new (MbimEventEntry, 1);
1952
        memcpy (&(entries[n_entries]->device_service_id), MBIM_UUID_BASIC_CONNECT, sizeof (MbimUuid));
1953
        entries[n_entries]->cids_count = 0;
1954
        entries[n_entries]->cids = g_new0 (guint32, 2);
1955
        if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY)
1956
            entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_SIGNAL_STATE;
1957
        if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES)
1958
            entries[n_entries]->cids[entries[n_entries]->cids_count++] = MBIM_CID_BASIC_CONNECT_REGISTER_STATE;
1959
        n_entries++;
1960
    }
1961
1962
    /* SMS service */
1963
    if (self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ) {
1964
        entries[n_entries] = g_new (MbimEventEntry, 1);
1965
        memcpy (&(entries[n_entries]->device_service_id), MBIM_UUID_SMS, sizeof (MbimUuid));
1966
        entries[n_entries]->cids_count = 2;
1967
        entries[n_entries]->cids = g_new0 (guint32, 2);
1968
        entries[n_entries]->cids[0] = MBIM_CID_SMS_READ;
1969
        entries[n_entries]->cids[1] = MBIM_CID_SMS_MESSAGE_STORE_STATUS;
1970
        n_entries++;
1971
    }
1972
1973
    request = (mbim_message_device_service_subscriber_list_set_new (
1974
                   n_entries,
1975
                   (const MbimEventEntry *const *)entries,
1976
                   NULL));
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1977
    mbim_device_command (device,
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1978
                         request,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1979
                         10,
1980
                         NULL,
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1981
                         (GAsyncReadyCallback)subscriber_list_set_ready_cb,
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
1982
                         result);
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
1983
    mbim_message_unref (request);
1984
    mbim_event_entry_array_free (entries);
1985
}
1986
1987
/*****************************************************************************/
1988
/* Enable/Disable unsolicited registration events */
1989
1990
static gboolean
1991
modem_3gpp_common_enable_disable_unsolicited_registration_events_finish (MMIfaceModem3gpp *self,
1992
                                                                         GAsyncResult *res,
1993
                                                                         GError **error)
1994
{
1995
    return common_enable_disable_unsolicited_events_finish (MM_BROADBAND_MODEM_MBIM (self), res, error);
1996
}
1997
1998
static void
1999
modem_3gpp_disable_unsolicited_registration_events (MMIfaceModem3gpp *self,
2000
                                                    gboolean cs_supported,
2001
                                                    gboolean ps_supported,
2002
                                                    gboolean eps_supported,
2003
                                                    GAsyncReadyCallback callback,
2004
                                                    gpointer user_data)
2005
{
2006
    MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES;
2007
    common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
2008
}
2009
2010
2011
static void
2012
modem_3gpp_enable_unsolicited_registration_events (MMIfaceModem3gpp *self,
2013
                                                   gboolean cs_supported,
2014
                                                   gboolean ps_supported,
2015
                                                   gboolean eps_supported,
2016
                                                   GAsyncReadyCallback callback,
2017
                                                   gpointer user_data)
2018
{
2019
    MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES;
2020
    common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
2021
}
2022
2023
/*****************************************************************************/
2024
/* Enable/Disable unsolicited events (3GPP interface) */
2025
2026
static gboolean
2027
modem_3gpp_common_enable_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
2028
                                                            GAsyncResult *res,
2029
                                                            GError **error)
2030
{
2031
    return common_enable_disable_unsolicited_events_finish (MM_BROADBAND_MODEM_MBIM (self), res, error);
2032
}
2033
2034
static void
2035
modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
2036
                                       GAsyncReadyCallback callback,
2037
                                       gpointer user_data)
2038
{
2039
    MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
2040
    common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
2041
}
2042
2043
static void
2044
modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
2045
                                      GAsyncReadyCallback callback,
2046
                                      gpointer user_data)
2047
{
2048
    MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY;
2049
    common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2050
}
2051
2052
/*****************************************************************************/
2053
/* Load operator name (3GPP interface) */
2054
2055
static gchar *
2056
modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *_self,
2057
                                      GAsyncResult *res,
2058
                                      GError **error)
2059
{
2060
    MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
2061
2062
    if (self->priv->current_operator_name)
2063
        return g_strdup (self->priv->current_operator_name);
2064
2065
    g_set_error (error,
2066
                 MM_CORE_ERROR,
2067
                 MM_CORE_ERROR_FAILED,
2068
                 "Current operator name is still unknown");
2069
    return NULL;
2070
}
2071
2072
static void
2073
modem_3gpp_load_operator_name (MMIfaceModem3gpp *self,
2074
                               GAsyncReadyCallback callback,
2075
                               gpointer user_data)
2076
{
2077
    GSimpleAsyncResult *result;
2078
2079
    /* Just finish the async operation */
2080
    result = g_simple_async_result_new (G_OBJECT (self),
2081
                                        callback,
2082
                                        user_data,
2083
                                        modem_3gpp_load_operator_name);
2084
    g_simple_async_result_set_op_res_gboolean (result, TRUE);
2085
    g_simple_async_result_complete_in_idle (result);
2086
    g_object_unref (result);
2087
}
2088
2089
/*****************************************************************************/
2090
/* Load operator code (3GPP interface) */
2091
2092
static gchar *
2093
modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *_self,
2094
                                      GAsyncResult *res,
2095
                                      GError **error)
2096
{
2097
    MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
2098
2099
    if (self->priv->current_operator_id)
2100
        return g_strdup (self->priv->current_operator_id);
2101
2102
    g_set_error (error,
2103
                 MM_CORE_ERROR,
2104
                 MM_CORE_ERROR_FAILED,
2105
                 "Current operator MCC/MNC is still unknown");
2106
    return NULL;
2107
}
2108
2109
static void
2110
modem_3gpp_load_operator_code (MMIfaceModem3gpp *self,
2111
                               GAsyncReadyCallback callback,
2112
                               gpointer user_data)
2113
{
2114
    GSimpleAsyncResult *result;
2115
2116
    /* Just finish the async operation */
2117
    result = g_simple_async_result_new (G_OBJECT (self),
2118
                                        callback,
2119
                                        user_data,
2120
                                        modem_3gpp_load_operator_code);
2121
    g_simple_async_result_set_op_res_gboolean (result, TRUE);
2122
    g_simple_async_result_complete_in_idle (result);
2123
    g_object_unref (result);
2124
}
2125
2126
/*****************************************************************************/
2127
/* Registration checks (3GPP interface) */
2128
2129
static gboolean
2130
modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self,
2131
                                           GAsyncResult *res,
2132
                                           GError **error)
2133
{
2134
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
2135
}
2136
2137
static void
2138
register_state_query_ready (MbimDevice *device,
2139
                            GAsyncResult *res,
2140
                            GSimpleAsyncResult *simple)
2141
{
2142
    MbimMessage *response;
2143
    GError *error = NULL;
2144
    MbimRegisterState register_state;
2145
    MbimDataClass available_data_classes;
2146
    gchar *provider_id;
2147
    gchar *provider_name;
2148
2149
    response = mbim_device_command_finish (device, res, &error);
2150
    if (response &&
2151
        mbim_message_command_done_get_result (response, &error) &&
2152
        mbim_message_register_state_response_parse (
2153
            response,
2154
            NULL, /* nw_error */
2155
            &register_state,
2156
            NULL, /* register_mode */
2157
            &available_data_classes,
2158
            NULL, /* current_cellular_class */
2159
            &provider_id,
2160
            &provider_name,
2161
            NULL, /* roaming_text */
2162
            NULL, /* registration_flag */
2163
            NULL)) {
2164
        MMBroadbandModemMbim *self;
2165
2166
        self = MM_BROADBAND_MODEM_MBIM (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
2167
        update_registration_info (self,
2168
                                  register_state,
2169
                                  available_data_classes,
2170
                                  provider_id,
2171
                                  provider_name);
2172
        g_object_unref (self);
2173
2174
        g_simple_async_result_set_op_res_gboolean (simple, TRUE);
2175
    } else
2176
        g_simple_async_result_take_error (simple, error);
2177
2178
    if (response)
2179
        mbim_message_unref (response);
2180
    g_simple_async_result_complete (simple);
2181
    g_object_unref (simple);
2182
}
2183
2184
static void
2185
modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self,
2186
                                    gboolean cs_supported,
2187
                                    gboolean ps_supported,
2188
                                    gboolean eps_supported,
2189
                                    GAsyncReadyCallback callback,
2190
                                    gpointer user_data)
2191
{
2192
    GSimpleAsyncResult *result;
2193
    MbimDevice *device;
2194
    MbimMessage *message;
2195
2196
    if (!peek_device (self, &device, callback, user_data))
2197
        return;
2198
2199
    result = g_simple_async_result_new (G_OBJECT (self),
2200
                                        callback,
2201
                                        user_data,
2202
                                        modem_3gpp_run_registration_checks);
2203
2204
    message = mbim_message_register_state_query_new (NULL);
2205
    mbim_device_command (device,
2206
                         message,
2207
                         10,
2208
                         NULL,
2209
                         (GAsyncReadyCallback)register_state_query_ready,
2210
                         result);
2211
    mbim_message_unref (message);
2212
}
2213
2214
/*****************************************************************************/
2215
2216
static gboolean
2217
modem_3gpp_register_in_network_finish (MMIfaceModem3gpp *self,
2218
                                       GAsyncResult *res,
2219
                                       GError **error)
2220
{
2221
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
2222
}
2223
2224
static void
2225
register_state_set_ready (MbimDevice *device,
2226
                          GAsyncResult *res,
2227
                          GSimpleAsyncResult *simple)
2228
{
2229
    MbimMessage *response;
2230
    GError *error = NULL;
2231
    MbimNwError nw_error;
2232
2233
    response = mbim_device_command_finish (device, res, &error);
2234
    if (response &&
2235
        mbim_message_command_done_get_result (response, &error) &&
2236
        mbim_message_register_state_response_parse (
2237
            response,
2238
            &nw_error,
2239
            NULL, /* &register_state */
2240
            NULL, /* register_mode */
2241
            NULL, /* available_data_classes */
2242
            NULL, /* current_cellular_class */
2243
            NULL, /* provider_id */
2244
            NULL, /* provider_name */
2245
            NULL, /* roaming_text */
2246
            NULL, /* registration_flag */
2247
            NULL)) {
2248
        if (nw_error)
2249
            error = mm_mobile_equipment_error_from_mbim_nw_error (nw_error);
2250
    }
2251
2252
    if (error)
2253
        g_simple_async_result_take_error (simple, error);
2254
    else
2255
        g_simple_async_result_set_op_res_gboolean (simple, TRUE);
2256
2257
    if (response)
2258
        mbim_message_unref (response);
2259
    g_simple_async_result_complete (simple);
2260
    g_object_unref (simple);
2261
}
2262
2263
static void
2264
modem_3gpp_register_in_network (MMIfaceModem3gpp *self,
2265
                                const gchar *operator_id,
2266
                                GCancellable *cancellable,
2267
                                GAsyncReadyCallback callback,
2268
                                gpointer user_data)
2269
{
2270
    GSimpleAsyncResult *result;
2271
    MbimDevice *device;
2272
    MbimMessage *message;
2273
2274
    if (!peek_device (self, &device, callback, user_data))
2275
        return;
2276
2277
    result = g_simple_async_result_new (G_OBJECT (self),
2278
                                        callback,
2279
                                        user_data,
1.2.3 by Michael Biebl
Import upstream version 1.2.0
2280
                                        modem_3gpp_register_in_network);
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2281
2282
    if (operator_id && operator_id[0])
2283
        message = (mbim_message_register_state_set_new (
2284
                       operator_id,
2285
                       MBIM_REGISTER_ACTION_MANUAL,
2286
                       0, /* data_class, none preferred */
2287
                       NULL));
2288
    else
2289
        message = (mbim_message_register_state_set_new (
2290
                       "",
2291
                       MBIM_REGISTER_ACTION_AUTOMATIC,
2292
                       0, /* data_class, none preferred */
2293
                       NULL));
2294
    mbim_device_command (device,
2295
                         message,
2296
                         60,
2297
                         NULL,
2298
                         (GAsyncReadyCallback)register_state_set_ready,
2299
                         result);
2300
    mbim_message_unref (message);
2301
}
2302
2303
/*****************************************************************************/
1.2.3 by Michael Biebl
Import upstream version 1.2.0
2304
/* Scan networks (3GPP interface) */
2305
2306
static GList *
2307
modem_3gpp_scan_networks_finish (MMIfaceModem3gpp *self,
2308
                                 GAsyncResult *res,
2309
                                 GError **error)
2310
{
2311
    MbimMessage *response;
2312
    MbimProvider **providers;
2313
    guint n_providers;
2314
    GList *info_list = NULL;
2315
2316
    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
2317
        return NULL;
2318
2319
    response = (MbimMessage *)g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
2320
    if (mbim_message_command_done_get_result (response, error) &&
2321
        mbim_message_visible_providers_response_parse (response,
2322
                                                       &n_providers,
2323
                                                       &providers,
2324
                                                       error)) {
2325
        info_list = mm_3gpp_network_info_list_from_mbim_providers ((const MbimProvider *const *)providers,
2326
                                                                   n_providers);
2327
        mbim_provider_array_free (providers);
2328
    }
2329
    return info_list;
2330
}
2331
2332
static void
2333
visible_providers_query_ready (MbimDevice *device,
2334
                               GAsyncResult *res,
2335
                               GSimpleAsyncResult *simple)
2336
{
2337
    MbimMessage *response;
2338
    GError *error = NULL;
2339
2340
    response = mbim_device_command_finish (device, res, &error);
2341
    if (response)
2342
        g_simple_async_result_set_op_res_gpointer (simple, response, (GDestroyNotify)mbim_message_unref);
2343
    else
2344
        g_simple_async_result_take_error (simple, error);
2345
2346
    g_simple_async_result_complete (simple);
2347
    g_object_unref (simple);
2348
}
2349
2350
static void
2351
modem_3gpp_scan_networks (MMIfaceModem3gpp *self,
2352
                          GAsyncReadyCallback callback,
2353
                          gpointer user_data)
2354
{
2355
    GSimpleAsyncResult *result;
2356
    MbimDevice *device;
2357
    MbimMessage *message;
2358
2359
    if (!peek_device (self, &device, callback, user_data))
2360
        return;
2361
2362
    result = g_simple_async_result_new (G_OBJECT (self),
2363
                                        callback,
2364
                                        user_data,
2365
                                        modem_3gpp_scan_networks);
2366
2367
    mm_dbg ("scanning networks...");
2368
    message = mbim_message_visible_providers_query_new (MBIM_VISIBLE_PROVIDERS_ACTION_FULL_SCAN, NULL);
2369
    mbim_device_command (device,
2370
                         message,
2371
                         120,
2372
                         NULL,
2373
                         (GAsyncReadyCallback)visible_providers_query_ready,
2374
                         result);
2375
    mbim_message_unref (message);
2376
}
2377
2378
/*****************************************************************************/
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
2379
/* Check support (Messaging interface) */
2380
2381
static gboolean
2382
messaging_check_support_finish (MMIfaceModemMessaging *self,
2383
                                GAsyncResult *res,
2384
                                GError **error)
2385
{
2386
    /* no error expected here */
2387
    return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res));
2388
}
2389
2390
static void
2391
messaging_check_support (MMIfaceModemMessaging *_self,
2392
                         GAsyncReadyCallback callback,
2393
                         gpointer user_data)
2394
{
2395
    MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
2396
    GSimpleAsyncResult *result;
2397
2398
    result = g_simple_async_result_new (G_OBJECT (self),
2399
                                        callback,
2400
                                        user_data,
2401
                                        messaging_check_support);
2402
2403
    /* We only handle 3GPP messaging (PDU based) currently */
2404
    if (self->priv->caps_sms & MBIM_SMS_CAPS_PDU_RECEIVE &&
2405
        self->priv->caps_sms & MBIM_SMS_CAPS_PDU_SEND) {
2406
        mm_dbg ("Messaging capabilities supported");
2407
        g_simple_async_result_set_op_res_gboolean (result, TRUE);
2408
    } else {
2409
        mm_dbg ("Messaging capabilities not supported by this modem");
2410
        g_simple_async_result_set_op_res_gboolean (result, FALSE);
2411
    }
2412
2413
    g_simple_async_result_complete_in_idle (result);
2414
    g_object_unref (result);
2415
}
2416
2417
/*****************************************************************************/
2418
/* Load supported storages (Messaging interface) */
2419
2420
static gboolean
2421
messaging_load_supported_storages_finish (MMIfaceModemMessaging *self,
2422
                                          GAsyncResult *res,
2423
                                          GArray **mem1,
2424
                                          GArray **mem2,
2425
                                          GArray **mem3,
2426
                                          GError **error)
2427
{
2428
    MMSmsStorage supported;
2429
2430
    *mem1 = g_array_sized_new (FALSE, FALSE, sizeof (MMSmsStorage), 2);
2431
    supported = MM_SMS_STORAGE_MT;
2432
    g_array_append_val (*mem1, supported);
2433
    *mem2 = g_array_ref (*mem1);
2434
    *mem3 = g_array_ref (*mem1);
2435
    return TRUE;
2436
}
2437
2438
static void
2439
messaging_load_supported_storages (MMIfaceModemMessaging *self,
2440
                                   GAsyncReadyCallback callback,
2441
                                   gpointer user_data)
2442
{
2443
    GSimpleAsyncResult *result;
2444
2445
    result = g_simple_async_result_new (G_OBJECT (self),
2446
                                        callback,
2447
                                        user_data,
2448
                                        messaging_load_supported_storages);
2449
    g_simple_async_result_set_op_res_gboolean (result, TRUE);
2450
    g_simple_async_result_complete_in_idle (result);
2451
    g_object_unref (result);
2452
}
2453
2454
/*****************************************************************************/
2455
/* Load initial SMS parts */
2456
2457
typedef struct {
2458
    MMBroadbandModemMbim *self;
2459
    GSimpleAsyncResult *result;
2460
} LoadInitialSmsPartsContext;
2461
2462
static void
2463
load_initial_sms_parts_context_complete_and_free (LoadInitialSmsPartsContext *ctx)
2464
{
2465
    g_simple_async_result_complete (ctx->result);
2466
    g_object_unref (ctx->result);
2467
    g_object_unref (ctx->self);
2468
    g_slice_free (LoadInitialSmsPartsContext, ctx);
2469
}
2470
2471
static gboolean
2472
load_initial_sms_parts_finish (MMIfaceModemMessaging *self,
2473
                               GAsyncResult *res,
2474
                               GError **error)
2475
{
2476
    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
2477
}
2478
2479
static void
2480
add_sms_part (MMBroadbandModemMbim *self,
2481
              const MbimSmsPduReadRecord *pdu)
2482
{
2483
    MMSmsPart *part;
2484
    GError *error = NULL;
2485
1.2.3 by Michael Biebl
Import upstream version 1.2.0
2486
    part = mm_sms_part_3gpp_new_from_binary_pdu (pdu->message_index,
2487
                                                 pdu->pdu_data,
2488
                                                 pdu->pdu_data_size,
2489
                                                 &error);
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
2490
    if (part) {
2491
        mm_dbg ("Correctly parsed PDU (%d)", pdu->message_index);
2492
        mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
2493
                                            part,
2494
                                            mm_sms_state_from_mbim_message_status (pdu->message_status),
2495
                                            MM_SMS_STORAGE_MT);
2496
    } else {
2497
        /* Don't treat the error as critical */
2498
        mm_dbg ("Error parsing PDU (%d): %s",
2499
                pdu->message_index,
2500
                error->message);
2501
        g_error_free (error);
2502
    }
2503
}
2504
2505
static void
2506
sms_read_query_ready (MbimDevice *device,
2507
                      GAsyncResult *res,
2508
                      LoadInitialSmsPartsContext *ctx)
2509
{
2510
    MbimMessage *response;
2511
    GError *error = NULL;
2512
    guint32 messages_count;
2513
    MbimSmsPduReadRecord **pdu_messages;
2514
2515
    response = mbim_device_command_finish (device, res, &error);
2516
    if (response &&
2517
        mbim_message_command_done_get_result (response, &error) &&
2518
        mbim_message_sms_read_response_parse (
2519
            response,
2520
            NULL,
2521
            &messages_count,
2522
            &pdu_messages,
2523
            NULL, /* cdma_messages */
2524
            &error)) {
2525
        guint i;
2526
2527
        for (i = 0; i < messages_count; i++)
2528
            add_sms_part (ctx->self, pdu_messages[i]);
2529
        mbim_sms_pdu_read_record_array_free (pdu_messages);
2530
    } else
2531
        g_simple_async_result_take_error (ctx->result, error);
2532
2533
    if (response)
2534
        mbim_message_unref (response);
2535
2536
    load_initial_sms_parts_context_complete_and_free (ctx);
2537
}
2538
2539
static void
2540
load_initial_sms_parts (MMIfaceModemMessaging *self,
2541
                        MMSmsStorage storage,
2542
                        GAsyncReadyCallback callback,
2543
                        gpointer user_data)
2544
{
2545
    LoadInitialSmsPartsContext *ctx;
2546
    MbimDevice *device;
2547
    MbimMessage *message;
2548
2549
    if (!peek_device (self, &device, callback, user_data))
2550
        return;
2551
2552
    g_assert (storage == MM_SMS_STORAGE_MT);
2553
2554
    ctx = g_slice_new0 (LoadInitialSmsPartsContext);
2555
    ctx->self = g_object_ref (self);
2556
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
2557
                                             callback,
2558
                                             user_data,
2559
                                             load_initial_sms_parts);
2560
2561
    mm_dbg ("loading SMS parts...");
2562
    message = mbim_message_sms_read_query_new (MBIM_SMS_FORMAT_PDU,
2563
                                               MBIM_SMS_FLAG_ALL,
2564
                                               0, /* message index, unused */
2565
                                               NULL);
2566
    mbim_device_command (device,
2567
                         message,
2568
                         10,
2569
                         NULL,
2570
                         (GAsyncReadyCallback)sms_read_query_ready,
2571
                         ctx);
2572
    mbim_message_unref (message);
2573
}
2574
2575
/*****************************************************************************/
2576
/* Setup/Cleanup unsolicited event handlers (Messaging interface) */
2577
2578
static gboolean
2579
common_setup_cleanup_unsolicited_events_messaging_finish (MMIfaceModemMessaging *self,
2580
                                                          GAsyncResult *res,
2581
                                                          GError **error)
2582
{
2583
    return common_setup_cleanup_unsolicited_events_finish (MM_BROADBAND_MODEM_MBIM (self), res, error);
2584
}
2585
2586
static void
2587
cleanup_unsolicited_events_messaging (MMIfaceModemMessaging *self,
2588
                                      GAsyncReadyCallback callback,
2589
                                      gpointer user_data)
2590
{
2591
    MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SMS_READ;
2592
    common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), FALSE, callback, user_data);
2593
}
2594
2595
static void
2596
setup_unsolicited_events_messaging (MMIfaceModemMessaging *self,
2597
                                    GAsyncReadyCallback callback,
2598
                                    gpointer user_data)
2599
{
2600
    MM_BROADBAND_MODEM_MBIM (self)->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_SMS_READ;
2601
    common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), TRUE, callback, user_data);
2602
}
2603
2604
/*****************************************************************************/
2605
/* Enable/Disable unsolicited event handlers (Messaging interface) */
2606
2607
static gboolean
2608
common_enable_disable_unsolicited_events_messaging_finish (MMIfaceModemMessaging *self,
2609
                                                           GAsyncResult *res,
2610
                                                           GError **error)
2611
{
2612
    return common_enable_disable_unsolicited_events_finish (MM_BROADBAND_MODEM_MBIM (self), res, error);
2613
}
2614
2615
static void
2616
disable_unsolicited_events_messaging (MMIfaceModemMessaging *self,
2617
                                      GAsyncReadyCallback callback,
2618
                                      gpointer user_data)
2619
{
2620
    MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags &= ~PROCESS_NOTIFICATION_FLAG_SMS_READ;
2621
    common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
2622
}
2623
2624
static void
2625
enable_unsolicited_events_messaging (MMIfaceModemMessaging *self,
2626
                                     GAsyncReadyCallback callback,
2627
                                     gpointer user_data)
2628
{
2629
    MM_BROADBAND_MODEM_MBIM (self)->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_SMS_READ;
2630
    common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_MBIM (self), callback, user_data);
2631
}
2632
2633
/*****************************************************************************/
2634
/* Create SMS (Messaging interface) */
2635
2636
static MMSms *
2637
messaging_create_sms (MMIfaceModemMessaging *self)
2638
{
2639
    return mm_sms_mbim_new (MM_BASE_MODEM (self));
2640
}
2641
2642
/*****************************************************************************/
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2643
2644
MMBroadbandModemMbim *
2645
mm_broadband_modem_mbim_new (const gchar *device,
2646
                             const gchar **drivers,
2647
                             const gchar *plugin,
2648
                             guint16 vendor_id,
2649
                             guint16 product_id)
2650
{
2651
    return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM,
2652
                         MM_BASE_MODEM_DEVICE, device,
2653
                         MM_BASE_MODEM_DRIVERS, drivers,
2654
                         MM_BASE_MODEM_PLUGIN, plugin,
2655
                         MM_BASE_MODEM_VENDOR_ID, vendor_id,
2656
                         MM_BASE_MODEM_PRODUCT_ID, product_id,
2657
                         NULL);
2658
}
2659
2660
static void
2661
mm_broadband_modem_mbim_init (MMBroadbandModemMbim *self)
2662
{
2663
    /* Initialize private data */
2664
    self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
2665
                                              MM_TYPE_BROADBAND_MODEM_MBIM,
2666
                                              MMBroadbandModemMbimPrivate);
2667
}
2668
2669
static void
2670
finalize (GObject *object)
2671
{
2672
    MMMbimPort *mbim;
2673
    MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (object);
2674
2675
    g_free (self->priv->caps_device_id);
2676
    g_free (self->priv->caps_firmware_info);
2677
    g_free (self->priv->current_operator_id);
2678
    g_free (self->priv->current_operator_name);
2679
2680
    mbim = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self));
2681
    /* If we did open the MBIM port during initialization, close it now */
2682
    if (mbim && mm_mbim_port_is_open (mbim)) {
2683
        mm_mbim_port_close (mbim, NULL, NULL);
2684
    }
2685
2686
    G_OBJECT_CLASS (mm_broadband_modem_mbim_parent_class)->finalize (object);
2687
}
2688
2689
static void
2690
iface_modem_init (MMIfaceModem *iface)
2691
{
2692
    /* Initialization steps */
2693
    iface->load_current_capabilities = modem_load_current_capabilities;
2694
    iface->load_current_capabilities_finish = modem_load_current_capabilities_finish;
2695
    iface->load_manufacturer = modem_load_manufacturer;
2696
    iface->load_manufacturer_finish = modem_load_manufacturer_finish;
2697
    iface->load_model = modem_load_model;
2698
    iface->load_model_finish = modem_load_model_finish;
2699
    iface->load_revision = modem_load_revision;
2700
    iface->load_revision_finish = modem_load_revision_finish;
2701
    iface->load_equipment_identifier = modem_load_equipment_identifier;
2702
    iface->load_equipment_identifier_finish = modem_load_equipment_identifier_finish;
2703
    iface->load_device_identifier = modem_load_device_identifier;
2704
    iface->load_device_identifier_finish = modem_load_device_identifier_finish;
2705
    iface->load_supported_modes = modem_load_supported_modes;
2706
    iface->load_supported_modes_finish = modem_load_supported_modes_finish;
2707
    iface->load_unlock_required = modem_load_unlock_required;
2708
    iface->load_unlock_required_finish = modem_load_unlock_required_finish;
2709
    iface->load_unlock_retries = modem_load_unlock_retries;
2710
    iface->load_unlock_retries_finish = modem_load_unlock_retries_finish;
2711
    iface->load_own_numbers = modem_load_own_numbers;
2712
    iface->load_own_numbers_finish = modem_load_own_numbers_finish;
2713
    iface->load_power_state = modem_load_power_state;
2714
    iface->load_power_state_finish = modem_load_power_state_finish;
2715
    iface->modem_power_up = modem_power_up;
2716
    iface->modem_power_up_finish = common_power_up_down_finish;
2717
    iface->modem_power_down = modem_power_down;
2718
    iface->modem_power_down_finish = common_power_up_down_finish;
2719
    iface->load_supported_ip_families = modem_load_supported_ip_families;
2720
    iface->load_supported_ip_families_finish = modem_load_supported_ip_families_finish;
2721
2722
    /* Unneeded things */
2723
    iface->modem_after_power_up = NULL;
2724
    iface->modem_after_power_up_finish = NULL;
2725
    iface->load_supported_charsets = NULL;
2726
    iface->load_supported_charsets_finish = NULL;
2727
    iface->setup_flow_control = NULL;
2728
    iface->setup_flow_control_finish = NULL;
2729
    iface->setup_charset = NULL;
2730
    iface->setup_charset_finish = NULL;
2731
    iface->load_signal_quality = NULL;
2732
    iface->load_signal_quality_finish = NULL;
2733
2734
    /* Create MBIM-specific SIM */
2735
    iface->create_sim = create_sim;
2736
    iface->create_sim_finish = create_sim_finish;
2737
2738
    /* Create MBIM-specific bearer */
2739
    iface->create_bearer = modem_create_bearer;
2740
    iface->create_bearer_finish = modem_create_bearer_finish;
2741
}
2742
2743
static void
2744
iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
2745
{
2746
    /* Initialization steps */
2747
    iface->load_imei = modem_3gpp_load_imei;
2748
    iface->load_imei_finish = modem_3gpp_load_imei_finish;
2749
    iface->load_enabled_facility_locks = modem_3gpp_load_enabled_facility_locks;
2750
    iface->load_enabled_facility_locks_finish = modem_3gpp_load_enabled_facility_locks_finish;
2751
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
2752
    iface->setup_unsolicited_events = setup_unsolicited_events_3gpp;
2753
    iface->setup_unsolicited_events_finish = common_setup_cleanup_unsolicited_events_3gpp_finish;
2754
    iface->cleanup_unsolicited_events = cleanup_unsolicited_events_3gpp;
2755
    iface->cleanup_unsolicited_events_finish = common_setup_cleanup_unsolicited_events_3gpp_finish;
2756
    iface->enable_unsolicited_events = modem_3gpp_enable_unsolicited_events;
2757
    iface->enable_unsolicited_events_finish = modem_3gpp_common_enable_disable_unsolicited_events_finish;
2758
    iface->disable_unsolicited_events = modem_3gpp_disable_unsolicited_events;
2759
    iface->disable_unsolicited_events_finish = modem_3gpp_common_enable_disable_unsolicited_events_finish;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2760
    iface->setup_unsolicited_registration_events = setup_unsolicited_registration_events;
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
2761
    iface->setup_unsolicited_registration_events_finish = common_setup_cleanup_unsolicited_events_3gpp_finish;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2762
    iface->cleanup_unsolicited_registration_events = cleanup_unsolicited_registration_events;
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
2763
    iface->cleanup_unsolicited_registration_events_finish = common_setup_cleanup_unsolicited_events_3gpp_finish;
2764
    iface->enable_unsolicited_registration_events = modem_3gpp_enable_unsolicited_registration_events;
2765
    iface->enable_unsolicited_registration_events_finish = modem_3gpp_common_enable_disable_unsolicited_registration_events_finish;
2766
    iface->disable_unsolicited_registration_events = modem_3gpp_disable_unsolicited_registration_events;
2767
    iface->disable_unsolicited_registration_events_finish = modem_3gpp_common_enable_disable_unsolicited_registration_events_finish;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2768
    iface->load_operator_code = modem_3gpp_load_operator_code;
2769
    iface->load_operator_code_finish = modem_3gpp_load_operator_code_finish;
2770
    iface->load_operator_name = modem_3gpp_load_operator_name;
2771
    iface->load_operator_name_finish = modem_3gpp_load_operator_name_finish;
2772
    iface->run_registration_checks = modem_3gpp_run_registration_checks;
2773
    iface->run_registration_checks_finish = modem_3gpp_run_registration_checks_finish;
2774
    iface->register_in_network = modem_3gpp_register_in_network;
2775
    iface->register_in_network_finish = modem_3gpp_register_in_network_finish;
1.2.3 by Michael Biebl
Import upstream version 1.2.0
2776
    iface->scan_networks = modem_3gpp_scan_networks;
2777
    iface->scan_networks_finish = modem_3gpp_scan_networks_finish;
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2778
}
2779
2780
static void
1.2.2 by Mathieu Trudel-Lapierre
Import upstream version 1.0.0
2781
iface_modem_messaging_init (MMIfaceModemMessaging *iface)
2782
{
2783
    iface->check_support = messaging_check_support;
2784
    iface->check_support_finish = messaging_check_support_finish;
2785
    iface->load_supported_storages = messaging_load_supported_storages;
2786
    iface->load_supported_storages_finish = messaging_load_supported_storages_finish;
2787
    iface->setup_sms_format = NULL;
2788
    iface->setup_sms_format_finish = NULL;
2789
    iface->set_default_storage = NULL;
2790
    iface->set_default_storage_finish = NULL;
2791
    iface->load_initial_sms_parts = load_initial_sms_parts;
2792
    iface->load_initial_sms_parts_finish = load_initial_sms_parts_finish;
2793
    iface->setup_unsolicited_events = setup_unsolicited_events_messaging;
2794
    iface->setup_unsolicited_events_finish = common_setup_cleanup_unsolicited_events_messaging_finish;
2795
    iface->cleanup_unsolicited_events = cleanup_unsolicited_events_messaging;
2796
    iface->cleanup_unsolicited_events_finish = common_setup_cleanup_unsolicited_events_messaging_finish;
2797
    iface->enable_unsolicited_events = enable_unsolicited_events_messaging;
2798
    iface->enable_unsolicited_events_finish = common_enable_disable_unsolicited_events_messaging_finish;
2799
    iface->disable_unsolicited_events = disable_unsolicited_events_messaging;
2800
    iface->disable_unsolicited_events_finish = common_enable_disable_unsolicited_events_messaging_finish;
2801
    iface->create_sms = messaging_create_sms;
2802
}
2803
2804
static void
1.2.1 by Mathieu Trudel-Lapierre
Import upstream version 0.7.991
2805
mm_broadband_modem_mbim_class_init (MMBroadbandModemMbimClass *klass)
2806
{
2807
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
2808
    MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
2809
2810
    g_type_class_add_private (object_class, sizeof (MMBroadbandModemMbimPrivate));
2811
2812
    object_class->finalize = finalize;
2813
2814
    broadband_modem_class->initialization_started = initialization_started;
2815
    broadband_modem_class->initialization_started_finish = initialization_started_finish;
2816
    broadband_modem_class->enabling_started = enabling_started;
2817
    broadband_modem_class->enabling_started_finish = enabling_started_finish;
2818
    /* Do not initialize the MBIM modem through AT commands */
2819
    broadband_modem_class->enabling_modem_init = NULL;
2820
    broadband_modem_class->enabling_modem_init_finish = NULL;
2821
}