PageRenderTime 82ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 1ms

/src/mm-broadband-modem-qmi.c

https://bitbucket.org/accelecon/modemmanager
C | 7658 lines | 6171 code | 1080 blank | 407 comment | 636 complexity | 5f40a7f99878fcded4c8cbb7d20245ec MD5 | raw file
Possible License(s): GPL-2.0
  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) 2012 Google Inc.
  14. */
  15. #include <config.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <unistd.h>
  20. #include <ctype.h>
  21. #include "mm-broadband-modem-qmi.h"
  22. #include "ModemManager.h"
  23. #include "mm-log.h"
  24. #include "mm-errors-types.h"
  25. #include "mm-modem-helpers.h"
  26. #include "mm-modem-helpers-qmi.h"
  27. #include "mm-iface-modem.h"
  28. #include "mm-iface-modem-3gpp.h"
  29. #include "mm-iface-modem-3gpp-ussd.h"
  30. #include "mm-iface-modem-cdma.h"
  31. #include "mm-iface-modem-messaging.h"
  32. #include "mm-iface-modem-location.h"
  33. #include "mm-iface-modem-firmware.h"
  34. #include "mm-sim-qmi.h"
  35. #include "mm-bearer-qmi.h"
  36. #include "mm-sms-qmi.h"
  37. static void iface_modem_init (MMIfaceModem *iface);
  38. static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
  39. static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface);
  40. static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
  41. static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
  42. static void iface_modem_location_init (MMIfaceModemLocation *iface);
  43. static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
  44. static MMIfaceModemLocation *iface_modem_location_parent;
  45. G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmi, mm_broadband_modem_qmi, MM_TYPE_BROADBAND_MODEM, 0,
  46. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
  47. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
  48. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_USSD, iface_modem_3gpp_ussd_init)
  49. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
  50. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
  51. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
  52. G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init))
  53. struct _MMBroadbandModemQmiPrivate {
  54. /* Cached device IDs, retrieved by the modem interface when loading device
  55. * IDs, and used afterwards in the 3GPP and CDMA interfaces. */
  56. gchar *imei;
  57. gchar *meid;
  58. gchar *esn;
  59. /* Cached supported frequency bands; in order to handle ANY */
  60. GArray *supported_bands;
  61. /* 3GPP and CDMA share unsolicited events setup/enable/disable/cleanup */
  62. gboolean unsolicited_events_enabled;
  63. gboolean unsolicited_events_setup;
  64. guint event_report_indication_id;
  65. #if defined WITH_NEWEST_QMI_COMMANDS
  66. guint signal_info_indication_id;
  67. #endif /* WITH_NEWEST_QMI_COMMANDS */
  68. /* 3GPP/CDMA registration helpers */
  69. gchar *current_operator_id;
  70. gchar *current_operator_description;
  71. gboolean unsolicited_registration_events_enabled;
  72. gboolean unsolicited_registration_events_setup;
  73. guint serving_system_indication_id;
  74. #if defined WITH_NEWEST_QMI_COMMANDS
  75. guint system_info_indication_id;
  76. #endif /* WITH_NEWEST_QMI_COMMANDS */
  77. /* Messaging helpers */
  78. gboolean messaging_unsolicited_events_enabled;
  79. gboolean messaging_unsolicited_events_setup;
  80. guint messaging_event_report_indication_id;
  81. /* Location helpers */
  82. MMModemLocationSource enabled_sources;
  83. guint location_event_report_indication_id;
  84. /* Firmware helpers */
  85. GList *firmware_list;
  86. MMFirmwareProperties *current_firmware;
  87. };
  88. /*****************************************************************************/
  89. static QmiClient *
  90. peek_qmi_client (MMBroadbandModemQmi *self,
  91. QmiService service,
  92. GError **error)
  93. {
  94. MMQmiPort *port;
  95. QmiClient *client;
  96. port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
  97. if (!port) {
  98. g_set_error (error,
  99. MM_CORE_ERROR,
  100. MM_CORE_ERROR_FAILED,
  101. "Couldn't peek QMI port");
  102. return NULL;
  103. }
  104. client = mm_qmi_port_peek_client (port,
  105. service,
  106. MM_QMI_PORT_FLAG_DEFAULT);
  107. if (!client)
  108. g_set_error (error,
  109. MM_CORE_ERROR,
  110. MM_CORE_ERROR_FAILED,
  111. "Couldn't peek client for service '%s'",
  112. qmi_service_get_string (service));
  113. return client;
  114. }
  115. static gboolean
  116. ensure_qmi_client (MMBroadbandModemQmi *self,
  117. QmiService service,
  118. QmiClient **o_client,
  119. GAsyncReadyCallback callback,
  120. gpointer user_data)
  121. {
  122. GError *error = NULL;
  123. QmiClient *client;
  124. client = peek_qmi_client (self, service, &error);
  125. if (!client) {
  126. g_simple_async_report_take_gerror_in_idle (
  127. G_OBJECT (self),
  128. callback,
  129. user_data,
  130. error);
  131. return FALSE;
  132. }
  133. *o_client = client;
  134. return TRUE;
  135. }
  136. /*****************************************************************************/
  137. /* Create Bearer (Modem interface) */
  138. static MMBearer *
  139. modem_create_bearer_finish (MMIfaceModem *self,
  140. GAsyncResult *res,
  141. GError **error)
  142. {
  143. MMBearer *bearer;
  144. bearer = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
  145. mm_dbg ("New bearer created at DBus path '%s'", mm_bearer_get_path (bearer));
  146. return g_object_ref (bearer);
  147. }
  148. static void
  149. modem_create_bearer (MMIfaceModem *self,
  150. MMBearerProperties *properties,
  151. GAsyncReadyCallback callback,
  152. gpointer user_data)
  153. {
  154. MMBearer *bearer;
  155. GSimpleAsyncResult *result;
  156. /* Set a new ref to the bearer object as result */
  157. result = g_simple_async_result_new (G_OBJECT (self),
  158. callback,
  159. user_data,
  160. modem_create_bearer);
  161. /* We just create a MMBearerQmi */
  162. mm_dbg ("Creating QMI bearer in QMI modem");
  163. bearer = mm_bearer_qmi_new (MM_BROADBAND_MODEM_QMI (self),
  164. properties);
  165. g_simple_async_result_set_op_res_gpointer (result, bearer, g_object_unref);
  166. g_simple_async_result_complete_in_idle (result);
  167. g_object_unref (result);
  168. }
  169. /*****************************************************************************/
  170. /* Current Capabilities loading (Modem interface) */
  171. typedef struct {
  172. MMBroadbandModemQmi *self;
  173. QmiClientNas *nas_client;
  174. QmiClientDms *dms_client;
  175. GSimpleAsyncResult *result;
  176. gboolean run_get_system_selection_preference;
  177. gboolean run_get_technology_preference;
  178. gboolean run_get_capabilities;
  179. MMModemCapability capabilities;
  180. } LoadCurrentCapabilitiesContext;
  181. static MMModemCapability
  182. modem_load_current_capabilities_finish (MMIfaceModem *self,
  183. GAsyncResult *res,
  184. GError **error)
  185. {
  186. MMModemCapability caps;
  187. gchar *caps_str;
  188. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  189. return MM_MODEM_CAPABILITY_NONE;
  190. caps = ((MMModemCapability) GPOINTER_TO_UINT (
  191. g_simple_async_result_get_op_res_gpointer (
  192. G_SIMPLE_ASYNC_RESULT (res))));
  193. caps_str = mm_modem_capability_build_string_from_mask (caps);
  194. mm_dbg ("loaded current capabilities: %s", caps_str);
  195. g_free (caps_str);
  196. return caps;
  197. }
  198. static void
  199. load_current_capabilities_context_complete_and_free (LoadCurrentCapabilitiesContext *ctx)
  200. {
  201. g_simple_async_result_complete_in_idle (ctx->result);
  202. g_object_unref (ctx->result);
  203. g_object_unref (ctx->nas_client);
  204. g_object_unref (ctx->dms_client);
  205. g_object_unref (ctx->self);
  206. g_free (ctx);
  207. }
  208. static void load_current_capabilities_context_step (LoadCurrentCapabilitiesContext *ctx);
  209. static void
  210. load_current_capabilities_get_capabilities_ready (QmiClientDms *client,
  211. GAsyncResult *res,
  212. LoadCurrentCapabilitiesContext *ctx)
  213. {
  214. QmiMessageDmsGetCapabilitiesOutput *output = NULL;
  215. GError *error = NULL;
  216. output = qmi_client_dms_get_capabilities_finish (client, res, &error);
  217. if (!output) {
  218. g_prefix_error (&error, "QMI operation failed: ");
  219. g_simple_async_result_take_error (ctx->result, error);
  220. } else if (!qmi_message_dms_get_capabilities_output_get_result (output, &error)) {
  221. g_prefix_error (&error, "Couldn't get Capabilities: ");
  222. g_simple_async_result_take_error (ctx->result, error);
  223. } else {
  224. guint i;
  225. guint mask = MM_MODEM_CAPABILITY_NONE;
  226. GArray *radio_interface_list;
  227. qmi_message_dms_get_capabilities_output_get_info (
  228. output,
  229. NULL, /* info_max_tx_channel_rate */
  230. NULL, /* info_max_rx_channel_rate */
  231. NULL, /* info_data_service_capability */
  232. NULL, /* info_sim_capability */
  233. &radio_interface_list,
  234. NULL);
  235. for (i = 0; i < radio_interface_list->len; i++) {
  236. mask |= mm_modem_capability_from_qmi_radio_interface (g_array_index (radio_interface_list,
  237. QmiDmsRadioInterface,
  238. i));
  239. }
  240. /* Final capabilities are the intersection between the Technology
  241. * Preference (ie, allowed modes) or SSP and the device's capabilities.
  242. * If the Technology Preference was "auto" or unknown we just fall back
  243. * to the Get Capabilities response.
  244. */
  245. if (ctx->capabilities == MM_MODEM_CAPABILITY_NONE)
  246. ctx->capabilities = mask;
  247. else
  248. ctx->capabilities &= mask;
  249. }
  250. if (output)
  251. qmi_message_dms_get_capabilities_output_unref (output);
  252. g_simple_async_result_set_op_res_gpointer (ctx->result, GUINT_TO_POINTER (ctx->capabilities), NULL);
  253. load_current_capabilities_context_complete_and_free (ctx);
  254. }
  255. static void
  256. load_current_capabilities_get_technology_preference_ready (QmiClientNas *client,
  257. GAsyncResult *res,
  258. LoadCurrentCapabilitiesContext *ctx)
  259. {
  260. QmiMessageNasGetTechnologyPreferenceOutput *output = NULL;
  261. GError *error = NULL;
  262. output = qmi_client_nas_get_technology_preference_finish (client, res, &error);
  263. if (!output) {
  264. mm_dbg ("QMI operation failed: %s", error->message);
  265. g_error_free (error);
  266. } else if (!qmi_message_nas_get_technology_preference_output_get_result (output, &error)) {
  267. mm_dbg ("Couldn't get technology preference: %s", error->message);
  268. g_error_free (error);
  269. } else {
  270. QmiNasRadioTechnologyPreference preference_mask;
  271. qmi_message_nas_get_technology_preference_output_get_active (
  272. output,
  273. &preference_mask,
  274. NULL, /* duration */
  275. NULL);
  276. if (preference_mask != QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AUTO) {
  277. gchar *str;
  278. str = qmi_nas_radio_technology_preference_build_string_from_mask (preference_mask);
  279. ctx->capabilities = mm_modem_capability_from_qmi_radio_technology_preference (preference_mask);
  280. mm_dbg ("%s modes reported in technology preference: '%s'",
  281. ctx->capabilities == MM_MODEM_CAPABILITY_NONE ? "Unsupported" : "Valid",
  282. str);
  283. g_free (str);
  284. }
  285. }
  286. if (output)
  287. qmi_message_nas_get_technology_preference_output_unref (output);
  288. /* Mark as TP already run */
  289. ctx->run_get_technology_preference = FALSE;
  290. /* Get DMS Capabilities too */
  291. load_current_capabilities_context_step (ctx);
  292. }
  293. static void
  294. load_current_capabilities_get_system_selection_preference_ready (QmiClientNas *client,
  295. GAsyncResult *res,
  296. LoadCurrentCapabilitiesContext *ctx)
  297. {
  298. QmiMessageNasGetSystemSelectionPreferenceOutput *output = NULL;
  299. GError *error = NULL;
  300. QmiNasRatModePreference mode_preference_mask = 0;
  301. output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error);
  302. if (!output) {
  303. mm_dbg ("QMI operation failed: %s", error->message);
  304. g_error_free (error);
  305. } else if (!qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) {
  306. mm_dbg ("Couldn't get system selection preference: %s", error->message);
  307. g_error_free (error);
  308. } else if (!qmi_message_nas_get_system_selection_preference_output_get_mode_preference (
  309. output,
  310. &mode_preference_mask,
  311. NULL)) {
  312. QmiNasBandPreference band_preference_mask;
  313. mm_dbg ("Mode preference not reported in system selection preference");
  314. if (qmi_message_nas_get_system_selection_preference_output_get_band_preference (
  315. output,
  316. &band_preference_mask,
  317. NULL)) {
  318. gchar *str;
  319. str = qmi_nas_band_preference_build_string_from_mask (band_preference_mask);
  320. ctx->capabilities = mm_modem_capability_from_qmi_band_preference (band_preference_mask);
  321. mm_dbg ("%s bands reported in system selection preference: '%s'",
  322. ctx->capabilities == MM_MODEM_CAPABILITY_NONE ? "Unsupported" : "Valid",
  323. str);
  324. g_free (str);
  325. /* Just the presence of the LTE band preference tells us it's LTE */
  326. if (qmi_message_nas_get_system_selection_preference_output_get_lte_band_preference (
  327. output,
  328. NULL,
  329. NULL)) {
  330. mm_dbg ("LTE band preference found");
  331. ctx->capabilities |= MM_MODEM_CAPABILITY_LTE;
  332. }
  333. } else
  334. mm_dbg ("Band preference not reported in system selection preference");
  335. } else {
  336. gchar *str;
  337. str = qmi_nas_rat_mode_preference_build_string_from_mask (mode_preference_mask);
  338. ctx->capabilities = mm_modem_capability_from_qmi_rat_mode_preference (mode_preference_mask);
  339. mm_dbg ("%s capabilities reported in system selection preference: '%s'",
  340. ctx->capabilities == MM_MODEM_CAPABILITY_NONE ? "Unsupported" : "Valid",
  341. str);
  342. g_free (str);
  343. }
  344. if (output)
  345. qmi_message_nas_get_system_selection_preference_output_unref (output);
  346. /* Mark as SSP already run */
  347. ctx->run_get_system_selection_preference = FALSE;
  348. /* If we got some value, cache it and go on to DMS Get Capabilities */
  349. if (ctx->capabilities != MM_MODEM_CAPABILITY_NONE)
  350. ctx->run_get_technology_preference = FALSE;
  351. load_current_capabilities_context_step (ctx);
  352. }
  353. static void
  354. load_current_capabilities_context_step (LoadCurrentCapabilitiesContext *ctx)
  355. {
  356. if (ctx->run_get_system_selection_preference) {
  357. qmi_client_nas_get_system_selection_preference (
  358. ctx->nas_client,
  359. NULL, /* no input */
  360. 5,
  361. NULL, /* cancellable */
  362. (GAsyncReadyCallback)load_current_capabilities_get_system_selection_preference_ready,
  363. ctx);
  364. return;
  365. }
  366. if (ctx->run_get_technology_preference) {
  367. qmi_client_nas_get_technology_preference (
  368. ctx->nas_client,
  369. NULL, /* no input */
  370. 5,
  371. NULL, /* cancellable */
  372. (GAsyncReadyCallback)load_current_capabilities_get_technology_preference_ready,
  373. ctx);
  374. return;
  375. }
  376. if (ctx->run_get_capabilities) {
  377. qmi_client_dms_get_capabilities (
  378. ctx->dms_client,
  379. NULL, /* no input */
  380. 5,
  381. NULL, /* cancellable */
  382. (GAsyncReadyCallback)load_current_capabilities_get_capabilities_ready,
  383. ctx);
  384. return;
  385. }
  386. g_simple_async_result_set_error (
  387. ctx->result,
  388. MM_CORE_ERROR,
  389. MM_CORE_ERROR_UNSUPPORTED,
  390. "Loading current capabilities is not supported by this device");
  391. load_current_capabilities_context_complete_and_free (ctx);
  392. }
  393. static void
  394. modem_load_current_capabilities (MMIfaceModem *self,
  395. GAsyncReadyCallback callback,
  396. gpointer user_data)
  397. {
  398. LoadCurrentCapabilitiesContext *ctx;
  399. QmiClient *nas_client = NULL;
  400. QmiClient *dms_client = NULL;
  401. /* Best way to get current capabilities (ie, enabled radios) is
  402. * Get System Selection Preference's "mode preference" TLV, but that's
  403. * only supported by NAS >= 1.1, meaning older Gobi devices don't
  404. * implement it.
  405. *
  406. * On these devices, the DMS Get Capabilities call appears to report
  407. * currently enabled radios, but this does not take the user's
  408. * technology preference into account.
  409. *
  410. * So in the absence of System Selection Preference, we check the
  411. * Technology Preference first, and if that is "AUTO" we fall back to
  412. * Get Capabilities.
  413. */
  414. mm_dbg ("loading current capabilities...");
  415. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  416. QMI_SERVICE_NAS, &nas_client,
  417. callback, user_data))
  418. return;
  419. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  420. QMI_SERVICE_DMS, &dms_client,
  421. callback, user_data))
  422. return;
  423. ctx = g_new0 (LoadCurrentCapabilitiesContext, 1);
  424. ctx->self = g_object_ref (self);
  425. ctx->nas_client = g_object_ref (nas_client);
  426. ctx->dms_client = g_object_ref (dms_client);
  427. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  428. callback,
  429. user_data,
  430. modem_load_current_capabilities);
  431. ctx->capabilities = MM_MODEM_CAPABILITY_NONE;
  432. /* System selection preference introduced in NAS 1.1 */
  433. ctx->run_get_system_selection_preference = qmi_client_check_version (nas_client, 1, 1);
  434. ctx->run_get_technology_preference = TRUE;
  435. ctx->run_get_capabilities = TRUE;
  436. load_current_capabilities_context_step (ctx);
  437. }
  438. /*****************************************************************************/
  439. /* Modem Capabilities loading (Modem interface) */
  440. static MMModemCapability
  441. modem_load_modem_capabilities_finish (MMIfaceModem *self,
  442. GAsyncResult *res,
  443. GError **error)
  444. {
  445. MMModemCapability caps;
  446. gchar *caps_str;
  447. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  448. return MM_MODEM_CAPABILITY_NONE;
  449. caps = ((MMModemCapability) GPOINTER_TO_UINT (
  450. g_simple_async_result_get_op_res_gpointer (
  451. G_SIMPLE_ASYNC_RESULT (res))));
  452. caps_str = mm_modem_capability_build_string_from_mask (caps);
  453. mm_dbg ("loaded modem capabilities: %s", caps_str);
  454. g_free (caps_str);
  455. return caps;
  456. }
  457. static void
  458. dms_get_capabilities_ready (QmiClientDms *client,
  459. GAsyncResult *res,
  460. GSimpleAsyncResult *simple)
  461. {
  462. QmiMessageDmsGetCapabilitiesOutput *output = NULL;
  463. GError *error = NULL;
  464. output = qmi_client_dms_get_capabilities_finish (client, res, &error);
  465. if (!output) {
  466. g_prefix_error (&error, "QMI operation failed: ");
  467. g_simple_async_result_take_error (simple, error);
  468. } else if (!qmi_message_dms_get_capabilities_output_get_result (output, &error)) {
  469. g_prefix_error (&error, "Couldn't get modem capabilities: ");
  470. g_simple_async_result_take_error (simple, error);
  471. } else {
  472. guint i;
  473. guint mask = MM_MODEM_CAPABILITY_NONE;
  474. GArray *radio_interface_list;
  475. qmi_message_dms_get_capabilities_output_get_info (
  476. output,
  477. NULL, /* info_max_tx_channel_rate */
  478. NULL, /* info_max_rx_channel_rate */
  479. NULL, /* info_data_service_capability */
  480. NULL, /* info_sim_capability */
  481. &radio_interface_list,
  482. NULL);
  483. for (i = 0; i < radio_interface_list->len; i++) {
  484. mask |= mm_modem_capability_from_qmi_radio_interface (g_array_index (radio_interface_list,
  485. QmiDmsRadioInterface,
  486. i));
  487. }
  488. g_simple_async_result_set_op_res_gpointer (simple,
  489. GUINT_TO_POINTER (mask),
  490. NULL);
  491. }
  492. if (output)
  493. qmi_message_dms_get_capabilities_output_unref (output);
  494. g_simple_async_result_complete (simple);
  495. g_object_unref (simple);
  496. }
  497. static void
  498. modem_load_modem_capabilities (MMIfaceModem *self,
  499. GAsyncReadyCallback callback,
  500. gpointer user_data)
  501. {
  502. GSimpleAsyncResult *result;
  503. QmiClient *client = NULL;
  504. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  505. QMI_SERVICE_DMS, &client,
  506. callback, user_data))
  507. return;
  508. result = g_simple_async_result_new (G_OBJECT (self),
  509. callback,
  510. user_data,
  511. modem_load_modem_capabilities);
  512. mm_dbg ("loading modem capabilities...");
  513. qmi_client_dms_get_capabilities (QMI_CLIENT_DMS (client),
  514. NULL,
  515. 5,
  516. NULL,
  517. (GAsyncReadyCallback)dms_get_capabilities_ready,
  518. result);
  519. }
  520. /*****************************************************************************/
  521. /* Manufacturer loading (Modem interface) */
  522. static gchar *
  523. modem_load_manufacturer_finish (MMIfaceModem *self,
  524. GAsyncResult *res,
  525. GError **error)
  526. {
  527. gchar *manufacturer;
  528. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  529. return NULL;
  530. manufacturer = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  531. mm_dbg ("loaded manufacturer: %s", manufacturer);
  532. return manufacturer;
  533. }
  534. static void
  535. dms_get_manufacturer_ready (QmiClientDms *client,
  536. GAsyncResult *res,
  537. GSimpleAsyncResult *simple)
  538. {
  539. QmiMessageDmsGetManufacturerOutput *output = NULL;
  540. GError *error = NULL;
  541. output = qmi_client_dms_get_manufacturer_finish (client, res, &error);
  542. if (!output) {
  543. g_prefix_error (&error, "QMI operation failed: ");
  544. g_simple_async_result_take_error (simple, error);
  545. } else if (!qmi_message_dms_get_manufacturer_output_get_result (output, &error)) {
  546. g_prefix_error (&error, "Couldn't get Manufacturer: ");
  547. g_simple_async_result_take_error (simple, error);
  548. } else {
  549. const gchar *str;
  550. qmi_message_dms_get_manufacturer_output_get_manufacturer (output, &str, NULL);
  551. g_simple_async_result_set_op_res_gpointer (simple,
  552. g_strdup (str),
  553. (GDestroyNotify)g_free);
  554. }
  555. if (output)
  556. qmi_message_dms_get_manufacturer_output_unref (output);
  557. g_simple_async_result_complete (simple);
  558. g_object_unref (simple);
  559. }
  560. static void
  561. modem_load_manufacturer (MMIfaceModem *self,
  562. GAsyncReadyCallback callback,
  563. gpointer user_data)
  564. {
  565. GSimpleAsyncResult *result;
  566. QmiClient *client = NULL;
  567. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  568. QMI_SERVICE_DMS, &client,
  569. callback, user_data))
  570. return;
  571. result = g_simple_async_result_new (G_OBJECT (self),
  572. callback,
  573. user_data,
  574. modem_load_manufacturer);
  575. mm_dbg ("loading manufacturer...");
  576. qmi_client_dms_get_manufacturer (QMI_CLIENT_DMS (client),
  577. NULL,
  578. 5,
  579. NULL,
  580. (GAsyncReadyCallback)dms_get_manufacturer_ready,
  581. result);
  582. }
  583. /*****************************************************************************/
  584. /* Model loading (Modem interface) */
  585. static gchar *
  586. modem_load_model_finish (MMIfaceModem *self,
  587. GAsyncResult *res,
  588. GError **error)
  589. {
  590. gchar *model;
  591. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  592. return NULL;
  593. model = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  594. mm_dbg ("loaded model: %s", model);
  595. return model;
  596. }
  597. static void
  598. dms_get_model_ready (QmiClientDms *client,
  599. GAsyncResult *res,
  600. GSimpleAsyncResult *simple)
  601. {
  602. QmiMessageDmsGetModelOutput *output = NULL;
  603. GError *error = NULL;
  604. output = qmi_client_dms_get_model_finish (client, res, &error);
  605. if (!output) {
  606. g_prefix_error (&error, "QMI operation failed: ");
  607. g_simple_async_result_take_error (simple, error);
  608. } else if (!qmi_message_dms_get_model_output_get_result (output, &error)) {
  609. g_prefix_error (&error, "Couldn't get Model: ");
  610. g_simple_async_result_take_error (simple, error);
  611. } else {
  612. const gchar *str;
  613. qmi_message_dms_get_model_output_get_model (output, &str, NULL);
  614. g_simple_async_result_set_op_res_gpointer (simple,
  615. g_strdup (str),
  616. (GDestroyNotify)g_free);
  617. }
  618. if (output)
  619. qmi_message_dms_get_model_output_unref (output);
  620. g_simple_async_result_complete (simple);
  621. g_object_unref (simple);
  622. }
  623. static void
  624. modem_load_model (MMIfaceModem *self,
  625. GAsyncReadyCallback callback,
  626. gpointer user_data)
  627. {
  628. GSimpleAsyncResult *result;
  629. QmiClient *client = NULL;
  630. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  631. QMI_SERVICE_DMS, &client,
  632. callback, user_data))
  633. return;
  634. result = g_simple_async_result_new (G_OBJECT (self),
  635. callback,
  636. user_data,
  637. modem_load_model);
  638. mm_dbg ("loading model...");
  639. qmi_client_dms_get_model (QMI_CLIENT_DMS (client),
  640. NULL,
  641. 5,
  642. NULL,
  643. (GAsyncReadyCallback)dms_get_model_ready,
  644. result);
  645. }
  646. /*****************************************************************************/
  647. /* Revision loading (Modem interface) */
  648. static gchar *
  649. modem_load_revision_finish (MMIfaceModem *self,
  650. GAsyncResult *res,
  651. GError **error)
  652. {
  653. gchar *revision;
  654. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  655. return NULL;
  656. revision = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  657. mm_dbg ("loaded revision: %s", revision);
  658. return revision;
  659. }
  660. static void
  661. dms_get_revision_ready (QmiClientDms *client,
  662. GAsyncResult *res,
  663. GSimpleAsyncResult *simple)
  664. {
  665. QmiMessageDmsGetRevisionOutput *output = NULL;
  666. GError *error = NULL;
  667. output = qmi_client_dms_get_revision_finish (client, res, &error);
  668. if (!output) {
  669. g_prefix_error (&error, "QMI operation failed: ");
  670. g_simple_async_result_take_error (simple, error);
  671. } else if (!qmi_message_dms_get_revision_output_get_result (output, &error)) {
  672. g_prefix_error (&error, "Couldn't get Revision: ");
  673. g_simple_async_result_take_error (simple, error);
  674. } else {
  675. const gchar *str;
  676. qmi_message_dms_get_revision_output_get_revision (output, &str, NULL);
  677. g_simple_async_result_set_op_res_gpointer (simple,
  678. g_strdup (str),
  679. (GDestroyNotify)g_free);
  680. }
  681. if (output)
  682. qmi_message_dms_get_revision_output_unref (output);
  683. g_simple_async_result_complete (simple);
  684. g_object_unref (simple);
  685. }
  686. static void
  687. modem_load_revision (MMIfaceModem *self,
  688. GAsyncReadyCallback callback,
  689. gpointer user_data)
  690. {
  691. GSimpleAsyncResult *result;
  692. QmiClient *client = NULL;
  693. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  694. QMI_SERVICE_DMS, &client,
  695. callback, user_data))
  696. return;
  697. result = g_simple_async_result_new (G_OBJECT (self),
  698. callback,
  699. user_data,
  700. modem_load_revision);
  701. mm_dbg ("loading revision...");
  702. qmi_client_dms_get_revision (QMI_CLIENT_DMS (client),
  703. NULL,
  704. 5,
  705. NULL,
  706. (GAsyncReadyCallback)dms_get_revision_ready,
  707. result);
  708. }
  709. /*****************************************************************************/
  710. /* Equipment Identifier loading (Modem interface) */
  711. typedef struct {
  712. MMBroadbandModemQmi *self;
  713. QmiClient *client;
  714. GSimpleAsyncResult *result;
  715. } LoadEquipmentIdentifierContext;
  716. static void
  717. load_equipment_identifier_context_complete_and_free (LoadEquipmentIdentifierContext *ctx)
  718. {
  719. g_simple_async_result_complete (ctx->result);
  720. g_object_unref (ctx->result);
  721. g_object_unref (ctx->client);
  722. g_object_unref (ctx->self);
  723. g_free (ctx);
  724. }
  725. static gchar *
  726. modem_load_equipment_identifier_finish (MMIfaceModem *self,
  727. GAsyncResult *res,
  728. GError **error)
  729. {
  730. gchar *equipment_identifier;
  731. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  732. return NULL;
  733. equipment_identifier = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  734. mm_dbg ("loaded equipment identifier: %s", equipment_identifier);
  735. return equipment_identifier;
  736. }
  737. static void
  738. dms_get_ids_ready (QmiClientDms *client,
  739. GAsyncResult *res,
  740. LoadEquipmentIdentifierContext *ctx)
  741. {
  742. QmiMessageDmsGetIdsOutput *output = NULL;
  743. GError *error = NULL;
  744. const gchar *str;
  745. output = qmi_client_dms_get_ids_finish (client, res, &error);
  746. if (!output) {
  747. g_prefix_error (&error, "QMI operation failed: ");
  748. g_simple_async_result_take_error (ctx->result, error);
  749. load_equipment_identifier_context_complete_and_free (ctx);
  750. return;
  751. }
  752. if (!qmi_message_dms_get_ids_output_get_result (output, &error)) {
  753. g_prefix_error (&error, "Couldn't get IDs: ");
  754. g_simple_async_result_take_error (ctx->result, error);
  755. qmi_message_dms_get_ids_output_unref (output);
  756. load_equipment_identifier_context_complete_and_free (ctx);
  757. return;
  758. }
  759. /* In order:
  760. * If we have a IMEI, use it...
  761. * Otherwise, if we have a ESN, use it...
  762. * Otherwise, if we have a MEID, use it...
  763. * Otherwise, 'unknown'
  764. */
  765. if (qmi_message_dms_get_ids_output_get_imei (output, &str, NULL) &&
  766. str[0] != '\0' && str[0] != '0') {
  767. g_free (ctx->self->priv->imei);
  768. ctx->self->priv->imei = g_strdup (str);
  769. }
  770. if (qmi_message_dms_get_ids_output_get_esn (output, &str, NULL) &&
  771. str[0] != '\0' && str[0] != '0') {
  772. g_free (ctx->self->priv->esn);
  773. ctx->self->priv->esn = g_strdup (str);
  774. }
  775. if (qmi_message_dms_get_ids_output_get_meid (output, &str, NULL) &&
  776. str[0] != '\0' && str[0] != '0') {
  777. g_free (ctx->self->priv->meid);
  778. ctx->self->priv->meid = g_strdup (str);
  779. }
  780. if (ctx->self->priv->imei)
  781. str = ctx->self->priv->imei;
  782. else if (ctx->self->priv->esn)
  783. str = ctx->self->priv->esn;
  784. else if (ctx->self->priv->meid)
  785. str = ctx->self->priv->meid;
  786. else
  787. str = "unknown";
  788. g_simple_async_result_set_op_res_gpointer (ctx->result,
  789. g_strdup (str),
  790. (GDestroyNotify)g_free);
  791. qmi_message_dms_get_ids_output_unref (output);
  792. load_equipment_identifier_context_complete_and_free (ctx);
  793. }
  794. static void
  795. modem_load_equipment_identifier (MMIfaceModem *self,
  796. GAsyncReadyCallback callback,
  797. gpointer user_data)
  798. {
  799. LoadEquipmentIdentifierContext *ctx;
  800. QmiClient *client = NULL;
  801. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  802. QMI_SERVICE_DMS, &client,
  803. callback, user_data))
  804. return;
  805. ctx = g_new (LoadEquipmentIdentifierContext, 1);
  806. ctx->self = g_object_ref (self);
  807. ctx->client = g_object_ref (client);
  808. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  809. callback,
  810. user_data,
  811. modem_load_equipment_identifier);
  812. mm_dbg ("loading equipment identifier...");
  813. qmi_client_dms_get_ids (QMI_CLIENT_DMS (client),
  814. NULL,
  815. 5,
  816. NULL,
  817. (GAsyncReadyCallback)dms_get_ids_ready,
  818. ctx);
  819. }
  820. /*****************************************************************************/
  821. /* Device identifier loading (Modem interface) */
  822. static gchar *
  823. modem_load_device_identifier_finish (MMIfaceModem *self,
  824. GAsyncResult *res,
  825. GError **error)
  826. {
  827. gchar *device_identifier;
  828. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  829. return NULL;
  830. device_identifier = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  831. mm_dbg ("loaded device identifier: %s", device_identifier);
  832. return device_identifier;
  833. }
  834. static void
  835. modem_load_device_identifier (MMIfaceModem *self,
  836. GAsyncReadyCallback callback,
  837. gpointer user_data)
  838. {
  839. GSimpleAsyncResult *result;
  840. gchar *device_identifier;
  841. mm_dbg ("loading device identifier...");
  842. result = g_simple_async_result_new (G_OBJECT (self),
  843. callback,
  844. user_data,
  845. modem_load_device_identifier);
  846. /* Just use dummy ATI/ATI1 replies, all the other internal info should be
  847. * enough for uniqueness */
  848. device_identifier = mm_broadband_modem_create_device_identifier (MM_BROADBAND_MODEM (self), "", "");
  849. g_simple_async_result_set_op_res_gpointer (result,
  850. device_identifier,
  851. (GDestroyNotify)g_free);
  852. g_simple_async_result_complete_in_idle (result);
  853. g_object_unref (result);
  854. }
  855. /*****************************************************************************/
  856. /* Own Numbers loading (Modem interface) */
  857. static GStrv
  858. modem_load_own_numbers_finish (MMIfaceModem *self,
  859. GAsyncResult *res,
  860. GError **error)
  861. {
  862. gchar **own_numbers;
  863. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  864. return NULL;
  865. own_numbers = g_new0 (gchar *, 2);
  866. own_numbers[0] = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  867. mm_dbg ("loaded own numbers: %s", own_numbers[0]);
  868. return own_numbers;
  869. }
  870. static void
  871. dms_get_msisdn_ready (QmiClientDms *client,
  872. GAsyncResult *res,
  873. GSimpleAsyncResult *simple)
  874. {
  875. QmiMessageDmsGetMsisdnOutput *output = NULL;
  876. GError *error = NULL;
  877. output = qmi_client_dms_get_msisdn_finish (client, res, &error);
  878. if (!output) {
  879. g_prefix_error (&error, "QMI operation failed: ");
  880. g_simple_async_result_take_error (simple, error);
  881. } else if (!qmi_message_dms_get_msisdn_output_get_result (output, &error)) {
  882. g_prefix_error (&error, "Couldn't get MSISDN: ");
  883. g_simple_async_result_take_error (simple, error);
  884. } else {
  885. const gchar *str = NULL;
  886. qmi_message_dms_get_msisdn_output_get_msisdn (output, &str, NULL);
  887. g_simple_async_result_set_op_res_gpointer (simple,
  888. g_strdup (str),
  889. (GDestroyNotify)g_free);
  890. }
  891. if (output)
  892. qmi_message_dms_get_msisdn_output_unref (output);
  893. g_simple_async_result_complete (simple);
  894. g_object_unref (simple);
  895. }
  896. static void
  897. modem_load_own_numbers (MMIfaceModem *self,
  898. GAsyncReadyCallback callback,
  899. gpointer user_data)
  900. {
  901. GSimpleAsyncResult *result;
  902. QmiClient *client = NULL;
  903. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  904. QMI_SERVICE_DMS, &client,
  905. callback, user_data))
  906. return;
  907. result = g_simple_async_result_new (G_OBJECT (self),
  908. callback,
  909. user_data,
  910. modem_load_own_numbers);
  911. mm_dbg ("loading own numbers...");
  912. qmi_client_dms_get_msisdn (QMI_CLIENT_DMS (client),
  913. NULL,
  914. 5,
  915. NULL,
  916. (GAsyncReadyCallback)dms_get_msisdn_ready,
  917. result);
  918. }
  919. /*****************************************************************************/
  920. /* Check if unlock required (Modem interface) */
  921. static MMModemLock
  922. modem_load_unlock_required_finish (MMIfaceModem *self,
  923. GAsyncResult *res,
  924. GError **error)
  925. {
  926. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  927. return MM_MODEM_LOCK_UNKNOWN;
  928. return (MMModemLock) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
  929. G_SIMPLE_ASYNC_RESULT (res)));
  930. }
  931. static void
  932. dms_uim_get_pin_status_ready (QmiClientDms *client,
  933. GAsyncResult *res,
  934. GSimpleAsyncResult *simple)
  935. {
  936. QmiMessageDmsUimGetPinStatusOutput *output;
  937. GError *error = NULL;
  938. output = qmi_client_dms_uim_get_pin_status_finish (client, res, &error);
  939. if (!output) {
  940. g_prefix_error (&error, "QMI operation failed: ");
  941. g_simple_async_result_take_error (simple, error);
  942. } else if (!qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) {
  943. /* When no SIM inserted, an internal error when checking PIN status
  944. * needs to be fatal so that we mark the modem unusable. */
  945. if (g_error_matches (error,
  946. QMI_PROTOCOL_ERROR,
  947. QMI_PROTOCOL_ERROR_INTERNAL)) {
  948. g_simple_async_result_set_error (simple,
  949. MM_MOBILE_EQUIPMENT_ERROR,
  950. MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE,
  951. "Couldn't get PIN status: %s",
  952. error->message);
  953. g_error_free (error);
  954. } else {
  955. g_prefix_error (&error, "Couldn't get PIN status: ");
  956. g_simple_async_result_take_error (simple, error);
  957. }
  958. } else {
  959. MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
  960. QmiDmsUimPinStatus current_status;
  961. if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
  962. output,
  963. &current_status,
  964. NULL, /* verify_retries_left */
  965. NULL, /* unblock_retries_left */
  966. NULL))
  967. lock = mm_modem_lock_from_qmi_uim_pin_status (current_status, TRUE);
  968. if (lock == MM_MODEM_LOCK_NONE &&
  969. qmi_message_dms_uim_get_pin_status_output_get_pin2_status (
  970. output,
  971. &current_status,
  972. NULL, /* verify_retries_left */
  973. NULL, /* unblock_retries_left */
  974. NULL))
  975. lock = mm_modem_lock_from_qmi_uim_pin_status (current_status, FALSE);
  976. g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (lock), NULL);
  977. }
  978. if (output)
  979. qmi_message_dms_uim_get_pin_status_output_unref (output);
  980. g_simple_async_result_complete (simple);
  981. g_object_unref (simple);
  982. }
  983. static void
  984. modem_load_unlock_required (MMIfaceModem *self,
  985. GAsyncReadyCallback callback,
  986. gpointer user_data)
  987. {
  988. GSimpleAsyncResult *result;
  989. QmiClient *client = NULL;
  990. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  991. QMI_SERVICE_DMS, &client,
  992. callback, user_data))
  993. return;
  994. result = g_simple_async_result_new (G_OBJECT (self),
  995. callback,
  996. user_data,
  997. modem_load_unlock_required);
  998. /* CDMA-only modems don't need this */
  999. if (mm_iface_modem_is_cdma_only (self)) {
  1000. mm_dbg ("Skipping unlock check in CDMA-only modem...");
  1001. g_simple_async_result_set_op_res_gpointer (result,
  1002. GUINT_TO_POINTER (MM_MODEM_LOCK_NONE),
  1003. NULL);
  1004. g_simple_async_result_complete_in_idle (result);
  1005. g_object_unref (result);
  1006. return;
  1007. }
  1008. mm_dbg ("loading unlock required...");
  1009. qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (client),
  1010. NULL,
  1011. 5,
  1012. NULL,
  1013. (GAsyncReadyCallback)dms_uim_get_pin_status_ready,
  1014. result);
  1015. }
  1016. /*****************************************************************************/
  1017. /* Check if unlock retries (Modem interface) */
  1018. static MMUnlockRetries *
  1019. modem_load_unlock_retries_finish (MMIfaceModem *self,
  1020. GAsyncResult *res,
  1021. GError **error)
  1022. {
  1023. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  1024. return NULL;
  1025. return MM_UNLOCK_RETRIES (g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
  1026. }
  1027. static void
  1028. retry_count_dms_uim_get_pin_status_ready (QmiClientDms *client,
  1029. GAsyncResult *res,
  1030. GSimpleAsyncResult *simple)
  1031. {
  1032. QmiMessageDmsUimGetPinStatusOutput *output;
  1033. GError *error = NULL;
  1034. output = qmi_client_dms_uim_get_pin_status_finish (client, res, &error);
  1035. if (!output) {
  1036. g_prefix_error (&error, "QMI operation failed: ");
  1037. g_simple_async_result_take_error (simple, error);
  1038. } else if (!qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) {
  1039. g_prefix_error (&error, "Couldn't get unlock retries: ");
  1040. g_simple_async_result_take_error (simple, error);
  1041. } else {
  1042. MMUnlockRetries *retries;
  1043. guint8 verify_retries_left;
  1044. guint8 unblock_retries_left;
  1045. retries = mm_unlock_retries_new ();
  1046. if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
  1047. output,
  1048. NULL, /* current_status */
  1049. &verify_retries_left,
  1050. &unblock_retries_left,
  1051. NULL)) {
  1052. mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, verify_retries_left);
  1053. mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, unblock_retries_left);
  1054. }
  1055. if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status (
  1056. output,
  1057. NULL, /* current_status */
  1058. &verify_retries_left,
  1059. &unblock_retries_left,
  1060. NULL)) {
  1061. mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN2, verify_retries_left);
  1062. mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK2, unblock_retries_left);
  1063. }
  1064. g_simple_async_result_set_op_res_gpointer (simple, retries, g_object_unref);
  1065. }
  1066. if (output)
  1067. qmi_message_dms_uim_get_pin_status_output_unref (output);
  1068. g_simple_async_result_complete (simple);
  1069. g_object_unref (simple);
  1070. }
  1071. static void
  1072. modem_load_unlock_retries (MMIfaceModem *self,
  1073. GAsyncReadyCallback callback,
  1074. gpointer user_data)
  1075. {
  1076. GSimpleAsyncResult *result;
  1077. QmiClient *client = NULL;
  1078. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1079. QMI_SERVICE_DMS, &client,
  1080. callback, user_data))
  1081. return;
  1082. result = g_simple_async_result_new (G_OBJECT (self),
  1083. callback,
  1084. user_data,
  1085. modem_load_unlock_retries);
  1086. mm_dbg ("loading unlock retries...");
  1087. qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (client),
  1088. NULL,
  1089. 5,
  1090. NULL,
  1091. (GAsyncReadyCallback)retry_count_dms_uim_get_pin_status_ready,
  1092. result);
  1093. }
  1094. /*****************************************************************************/
  1095. /* Load supported bands (Modem interface) */
  1096. static GArray *
  1097. modem_load_supported_bands_finish (MMIfaceModem *_self,
  1098. GAsyncResult *res,
  1099. GError **error)
  1100. {
  1101. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  1102. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  1103. return NULL;
  1104. if (self->priv->supported_bands)
  1105. g_array_unref (self->priv->supported_bands);
  1106. /* Cache the supported bands value */
  1107. self->priv->supported_bands = g_array_ref (g_simple_async_result_get_op_res_gpointer (
  1108. G_SIMPLE_ASYNC_RESULT (res)));
  1109. return g_array_ref (self->priv->supported_bands);
  1110. }
  1111. static void
  1112. dms_get_band_capabilities_ready (QmiClientDms *client,
  1113. GAsyncResult *res,
  1114. GSimpleAsyncResult *simple)
  1115. {
  1116. QmiMessageDmsGetBandCapabilitiesOutput *output;
  1117. GError *error = NULL;
  1118. output = qmi_client_dms_get_band_capabilities_finish (client, res, &error);
  1119. if (!output) {
  1120. g_prefix_error (&error, "QMI operation failed: ");
  1121. g_simple_async_result_take_error (simple, error);
  1122. } else if (!qmi_message_dms_get_band_capabilities_output_get_result (output, &error)) {
  1123. g_prefix_error (&error, "Couldn't get band capabilities: ");
  1124. g_simple_async_result_take_error (simple, error);
  1125. } else {
  1126. GArray *mm_bands;
  1127. QmiDmsBandCapability qmi_bands = 0;
  1128. QmiDmsLteBandCapability qmi_lte_bands = 0;
  1129. qmi_message_dms_get_band_capabilities_output_get_band_capability (
  1130. output,
  1131. &qmi_bands,
  1132. NULL);
  1133. qmi_message_dms_get_band_capabilities_output_get_lte_band_capability (
  1134. output,
  1135. &qmi_lte_bands,
  1136. NULL);
  1137. mm_bands = mm_modem_bands_from_qmi_band_capabilities (qmi_bands, qmi_lte_bands);
  1138. if (mm_bands->len == 0) {
  1139. g_array_unref (mm_bands);
  1140. g_simple_async_result_set_error (simple,
  1141. MM_CORE_ERROR,
  1142. MM_CORE_ERROR_FAILED,
  1143. "Couldn't parse the list of supported bands");
  1144. } else {
  1145. g_simple_async_result_set_op_res_gpointer (simple,
  1146. mm_bands,
  1147. (GDestroyNotify)g_array_unref);
  1148. }
  1149. }
  1150. if (output)
  1151. qmi_message_dms_get_band_capabilities_output_unref (output);
  1152. g_simple_async_result_complete (simple);
  1153. g_object_unref (simple);
  1154. }
  1155. static void
  1156. modem_load_supported_bands (MMIfaceModem *self,
  1157. GAsyncReadyCallback callback,
  1158. gpointer user_data)
  1159. {
  1160. GSimpleAsyncResult *result;
  1161. QmiClient *client = NULL;
  1162. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1163. QMI_SERVICE_DMS, &client,
  1164. callback, user_data))
  1165. return;
  1166. result = g_simple_async_result_new (G_OBJECT (self),
  1167. callback,
  1168. user_data,
  1169. modem_load_supported_bands);
  1170. mm_dbg ("loading band capabilities...");
  1171. qmi_client_dms_get_band_capabilities (QMI_CLIENT_DMS (client),
  1172. NULL,
  1173. 5,
  1174. NULL,
  1175. (GAsyncReadyCallback)dms_get_band_capabilities_ready,
  1176. result);
  1177. }
  1178. /*****************************************************************************/
  1179. /* Load current bands (Modem interface) */
  1180. static GArray *
  1181. modem_load_current_bands_finish (MMIfaceModem *self,
  1182. GAsyncResult *res,
  1183. GError **error)
  1184. {
  1185. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  1186. return NULL;
  1187. return (GArray *) g_array_ref (g_simple_async_result_get_op_res_gpointer (
  1188. G_SIMPLE_ASYNC_RESULT (res)));
  1189. }
  1190. #if defined WITH_NEWEST_QMI_COMMANDS
  1191. static void
  1192. nas_get_rf_band_information_ready (QmiClientNas *client,
  1193. GAsyncResult *res,
  1194. GSimpleAsyncResult *simple)
  1195. {
  1196. QmiMessageNasGetRfBandInformationOutput *output;
  1197. GError *error = NULL;
  1198. output = qmi_client_nas_get_rf_band_information_finish (client, res, &error);
  1199. if (!output) {
  1200. g_prefix_error (&error, "QMI operation failed: ");
  1201. g_simple_async_result_take_error (simple, error);
  1202. } else if (!qmi_message_nas_get_rf_band_information_output_get_result (output, &error)) {
  1203. g_prefix_error (&error, "Couldn't get current band information: ");
  1204. g_simple_async_result_take_error (simple, error);
  1205. } else {
  1206. GArray *mm_bands;
  1207. GArray *info_array = NULL;
  1208. qmi_message_nas_get_rf_band_information_output_get_list (output, &info_array, NULL);
  1209. mm_bands = mm_modem_bands_from_qmi_rf_band_information_array (info_array);
  1210. if (mm_bands->len == 0) {
  1211. g_array_unref (mm_bands);
  1212. g_simple_async_result_set_error (simple,
  1213. MM_CORE_ERROR,
  1214. MM_CORE_ERROR_FAILED,
  1215. "Couldn't parse the list of current bands");
  1216. } else {
  1217. g_simple_async_result_set_op_res_gpointer (simple,
  1218. mm_bands,
  1219. (GDestroyNotify)g_array_unref);
  1220. }
  1221. }
  1222. if (output)
  1223. qmi_message_nas_get_rf_band_information_output_unref (output);
  1224. g_simple_async_result_complete (simple);
  1225. g_object_unref (simple);
  1226. }
  1227. #endif /* WITH_NEWEST_QMI_COMMANDS */
  1228. static void
  1229. load_bands_get_system_selection_preference_ready (QmiClientNas *client,
  1230. GAsyncResult *res,
  1231. GSimpleAsyncResult *simple)
  1232. {
  1233. QmiMessageNasGetSystemSelectionPreferenceOutput *output = NULL;
  1234. GError *error = NULL;
  1235. output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error);
  1236. if (!output) {
  1237. g_prefix_error (&error, "QMI operation failed: ");
  1238. g_simple_async_result_take_error (simple, error);
  1239. } else if (!qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) {
  1240. g_prefix_error (&error, "Couldn't get system selection preference: ");
  1241. g_simple_async_result_take_error (simple, error);
  1242. } else {
  1243. GArray *mm_bands;
  1244. QmiNasBandPreference band_preference_mask = 0;
  1245. QmiNasLteBandPreference lte_band_preference_mask = 0;
  1246. qmi_message_nas_get_system_selection_preference_output_get_band_preference (
  1247. output,
  1248. &band_preference_mask,
  1249. NULL);
  1250. qmi_message_nas_get_system_selection_preference_output_get_lte_band_preference (
  1251. output,
  1252. &lte_band_preference_mask,
  1253. NULL);
  1254. mm_bands = mm_modem_bands_from_qmi_band_preference (band_preference_mask,
  1255. lte_band_preference_mask);
  1256. if (mm_bands->len == 0) {
  1257. g_array_unref (mm_bands);
  1258. g_simple_async_result_set_error (simple,
  1259. MM_CORE_ERROR,
  1260. MM_CORE_ERROR_FAILED,
  1261. "Couldn't parse the list of current bands");
  1262. } else {
  1263. gchar *str;
  1264. str = qmi_nas_band_preference_build_string_from_mask (band_preference_mask);
  1265. mm_dbg ("Bands reported in system selection preference: '%s'", str);
  1266. g_free (str);
  1267. g_simple_async_result_set_op_res_gpointer (simple,
  1268. mm_bands,
  1269. (GDestroyNotify)g_array_unref);
  1270. }
  1271. }
  1272. if (output)
  1273. qmi_message_nas_get_system_selection_preference_output_unref (output);
  1274. g_simple_async_result_complete (simple);
  1275. g_object_unref (simple);
  1276. }
  1277. static void
  1278. modem_load_current_bands (MMIfaceModem *self,
  1279. GAsyncReadyCallback callback,
  1280. gpointer user_data)
  1281. {
  1282. GSimpleAsyncResult *result;
  1283. QmiClient *client = NULL;
  1284. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1285. QMI_SERVICE_NAS, &client,
  1286. callback, user_data))
  1287. return;
  1288. result = g_simple_async_result_new (G_OBJECT (self),
  1289. callback,
  1290. user_data,
  1291. modem_load_current_bands);
  1292. mm_dbg ("loading current bands...");
  1293. #if defined WITH_NEWEST_QMI_COMMANDS
  1294. /* Introduced in NAS 1.19 */
  1295. if (qmi_client_check_version (ctx->client, 1, 19)) {
  1296. qmi_client_nas_get_rf_band_information (QMI_CLIENT_NAS (client),
  1297. NULL,
  1298. 5,
  1299. NULL,
  1300. (GAsyncReadyCallback)nas_get_rf_band_information_ready,
  1301. result);
  1302. return;
  1303. }
  1304. #endif
  1305. qmi_client_nas_get_system_selection_preference (
  1306. QMI_CLIENT_NAS (client),
  1307. NULL, /* no input */
  1308. 5,
  1309. NULL, /* cancellable */
  1310. (GAsyncReadyCallback)load_bands_get_system_selection_preference_ready,
  1311. result);
  1312. }
  1313. /*****************************************************************************/
  1314. /* Set bands (Modem interface) */
  1315. static gboolean
  1316. set_bands_finish (MMIfaceModem *self,
  1317. GAsyncResult *res,
  1318. GError **error)
  1319. {
  1320. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  1321. }
  1322. static void
  1323. bands_set_system_selection_preference_ready (QmiClientNas *client,
  1324. GAsyncResult *res,
  1325. GSimpleAsyncResult *simple)
  1326. {
  1327. QmiMessageNasSetSystemSelectionPreferenceOutput *output = NULL;
  1328. GError *error = NULL;
  1329. output = qmi_client_nas_set_system_selection_preference_finish (client, res, &error);
  1330. if (!output) {
  1331. g_prefix_error (&error, "QMI operation failed: ");
  1332. g_simple_async_result_take_error (simple, error);
  1333. } else if (!qmi_message_nas_set_system_selection_preference_output_get_result (output, &error)) {
  1334. g_prefix_error (&error, "Couldn't set system selection preference: ");
  1335. g_simple_async_result_take_error (simple, error);
  1336. } else
  1337. /* Good! TODO: do we really need to wait for the indication? */
  1338. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  1339. if (output)
  1340. qmi_message_nas_set_system_selection_preference_output_unref (output);
  1341. g_simple_async_result_complete (simple);
  1342. g_object_unref (simple);
  1343. }
  1344. static void
  1345. set_bands (MMIfaceModem *_self,
  1346. GArray *bands_array,
  1347. GAsyncReadyCallback callback,
  1348. gpointer user_data)
  1349. {
  1350. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  1351. QmiMessageNasSetSystemSelectionPreferenceInput *input;
  1352. GSimpleAsyncResult *result;
  1353. QmiClient *client = NULL;
  1354. QmiNasBandPreference qmi_bands = 0;
  1355. QmiNasLteBandPreference qmi_lte_bands = 0;
  1356. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1357. QMI_SERVICE_NAS, &client,
  1358. callback, user_data))
  1359. return;
  1360. result = g_simple_async_result_new (G_OBJECT (self),
  1361. callback,
  1362. user_data,
  1363. set_bands);
  1364. /* Handle ANY separately */
  1365. if (bands_array->len == 1 &&
  1366. g_array_index (bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
  1367. if (!self->priv->supported_bands) {
  1368. g_simple_async_result_set_error (result,
  1369. MM_CORE_ERROR,
  1370. MM_CORE_ERROR_FAILED,
  1371. "Cannot handle 'ANY' if supported bands are unknown");
  1372. g_simple_async_result_complete_in_idle (result);
  1373. g_object_unref (result);
  1374. return;
  1375. }
  1376. mm_modem_bands_to_qmi_band_preference (self->priv->supported_bands,
  1377. &qmi_bands,
  1378. &qmi_lte_bands);
  1379. } else
  1380. mm_modem_bands_to_qmi_band_preference (bands_array,
  1381. &qmi_bands,
  1382. &qmi_lte_bands);
  1383. input = qmi_message_nas_set_system_selection_preference_input_new ();
  1384. qmi_message_nas_set_system_selection_preference_input_set_band_preference (input, qmi_bands, NULL);
  1385. if (mm_iface_modem_is_3gpp_lte (_self))
  1386. qmi_message_nas_set_system_selection_preference_input_set_lte_band_preference (input, qmi_lte_bands, NULL);
  1387. qmi_message_nas_set_system_selection_preference_input_set_change_duration (input, QMI_NAS_CHANGE_DURATION_PERMANENT, NULL);
  1388. qmi_client_nas_set_system_selection_preference (
  1389. QMI_CLIENT_NAS (client),
  1390. input,
  1391. 5,
  1392. NULL, /* cancellable */
  1393. (GAsyncReadyCallback)bands_set_system_selection_preference_ready,
  1394. result);
  1395. qmi_message_nas_set_system_selection_preference_input_unref (input);
  1396. }
  1397. /*****************************************************************************/
  1398. /* Load supported modes (Modem interface) */
  1399. static MMModemMode
  1400. modem_load_supported_modes_finish (MMIfaceModem *self,
  1401. GAsyncResult *res,
  1402. GError **error)
  1403. {
  1404. return (MMModemMode)GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
  1405. G_SIMPLE_ASYNC_RESULT (res)));
  1406. }
  1407. static void
  1408. modem_load_supported_modes (MMIfaceModem *self,
  1409. GAsyncReadyCallback callback,
  1410. gpointer user_data)
  1411. {
  1412. GSimpleAsyncResult *result;
  1413. MMModemMode mode;
  1414. /* For QMI-powered modems, it is safe to assume they do 2G and 3G */
  1415. mode = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
  1416. /* Then, if the modem has LTE caps, it does 4G */
  1417. if (mm_iface_modem_is_3gpp_lte (MM_IFACE_MODEM (self)))
  1418. mode |= MM_MODEM_MODE_4G;
  1419. result = g_simple_async_result_new (G_OBJECT (self),
  1420. callback,
  1421. user_data,
  1422. modem_load_supported_modes);
  1423. g_simple_async_result_set_op_res_gpointer (result,
  1424. GUINT_TO_POINTER (mode),
  1425. NULL);
  1426. g_simple_async_result_complete_in_idle (result);
  1427. g_object_unref (result);
  1428. }
  1429. /*****************************************************************************/
  1430. /* Load signal quality (Modem interface) */
  1431. /* Limit the value betweeen [-113,-51] and scale it to a percentage */
  1432. #define STRENGTH_TO_QUALITY(strength) \
  1433. (guint8)(100 - ((CLAMP (strength, -113, -51) + 51) * 100 / (-113 + 51)))
  1434. typedef struct {
  1435. MMBroadbandModemQmi *self;
  1436. QmiClient *client;
  1437. GSimpleAsyncResult *result;
  1438. } LoadSignalQualityContext;
  1439. static void
  1440. load_signal_quality_context_complete_and_free (LoadSignalQualityContext *ctx)
  1441. {
  1442. g_simple_async_result_complete (ctx->result);
  1443. g_object_unref (ctx->result);
  1444. g_object_unref (ctx->client);
  1445. g_object_unref (ctx->self);
  1446. g_free (ctx);
  1447. }
  1448. static guint
  1449. load_signal_quality_finish (MMIfaceModem *self,
  1450. GAsyncResult *res,
  1451. GError **error)
  1452. {
  1453. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  1454. return 0;
  1455. return GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
  1456. G_SIMPLE_ASYNC_RESULT (res)));
  1457. }
  1458. #if defined WITH_NEWEST_QMI_COMMANDS
  1459. static gint8
  1460. signal_info_get_quality (MMBroadbandModemQmi *self,
  1461. QmiMessageNasGetSignalInfoOutput *output)
  1462. {
  1463. gint8 rssi_max = 0;
  1464. gint8 rssi;
  1465. guint8 quality;
  1466. /* We do not report per-technology signal quality, so just get the highest
  1467. * one of the ones reported. */
  1468. if (qmi_message_nas_get_signal_info_output_get_cdma_signal_strength (output, &rssi, NULL, NULL)) {
  1469. mm_dbg ("RSSI (CDMA): %d dBm", rssi);
  1470. rssi = MAX (rssi, rssi_max);
  1471. }
  1472. if (qmi_message_nas_get_signal_info_output_get_hdr_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) {
  1473. mm_dbg ("RSSI (HDR): %d dBm", rssi);
  1474. rssi = MAX (rssi, rssi_max);
  1475. }
  1476. if (qmi_message_nas_get_signal_info_output_get_gsm_signal_strength (output, &rssi, NULL)) {
  1477. mm_dbg ("RSSI (GSM): %d dBm", rssi);
  1478. rssi = MAX (rssi, rssi_max);
  1479. }
  1480. if (qmi_message_nas_get_signal_info_output_get_wcdma_signal_strength (output, &rssi, NULL, NULL)) {
  1481. mm_dbg ("RSSI (WCDMA): %d dBm", rssi);
  1482. rssi = MAX (rssi, rssi_max);
  1483. }
  1484. if (qmi_message_nas_get_signal_info_output_get_lte_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) {
  1485. mm_dbg ("RSSI (LTE): %d dBm", rssi);
  1486. rssi = MAX (rssi, rssi_max);
  1487. }
  1488. /* This RSSI comes as negative dBms */
  1489. quality = STRENGTH_TO_QUALITY (rssi_max);
  1490. mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, quality);
  1491. return quality;
  1492. }
  1493. static void
  1494. get_signal_info_ready (QmiClientNas *client,
  1495. GAsyncResult *res,
  1496. LoadSignalQualityContext *ctx)
  1497. {
  1498. QmiMessageNasGetSignalInfoOutput *output;
  1499. GError *error = NULL;
  1500. guint quality;
  1501. output = qmi_client_nas_get_signal_info_finish (client, res, &error);
  1502. if (!output) {
  1503. g_simple_async_result_take_error (ctx->result, error);
  1504. load_signal_quality_context_complete_and_free (ctx);
  1505. return;
  1506. }
  1507. if (!qmi_message_nas_get_signal_info_output_get_result (output, &error)) {
  1508. qmi_message_nas_get_signal_info_output_unref (output);
  1509. g_simple_async_result_take_error (ctx->result, error);
  1510. load_signal_quality_context_complete_and_free (ctx);
  1511. return;
  1512. }
  1513. quality = signal_info_get_quality (ctx->self, output);
  1514. g_simple_async_result_set_op_res_gpointer (
  1515. ctx->result,
  1516. GUINT_TO_POINTER (quality),
  1517. NULL);
  1518. qmi_message_nas_get_signal_info_output_unref (output);
  1519. load_signal_quality_context_complete_and_free (ctx);
  1520. }
  1521. #endif /* WITH_NEWEST_QMI_COMMANDS */
  1522. static void
  1523. signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self,
  1524. QmiMessageNasGetSignalStrengthOutput *output,
  1525. guint8 *o_quality,
  1526. MMModemAccessTechnology *o_act)
  1527. {
  1528. GArray *array = NULL;
  1529. gint8 signal_max;
  1530. QmiNasRadioInterface main_interface;
  1531. MMModemAccessTechnology act;
  1532. guint8 quality;
  1533. /* We do not report per-technology signal quality, so just get the highest
  1534. * one of the ones reported. */
  1535. /* The mandatory one is always present */
  1536. qmi_message_nas_get_signal_strength_output_get_signal_strength (output, &signal_max, &main_interface, NULL);
  1537. mm_dbg ("Signal strength (%s): %d dBm",
  1538. qmi_nas_radio_interface_get_string (main_interface),
  1539. signal_max);
  1540. act = mm_modem_access_technology_from_qmi_radio_interface (main_interface);
  1541. /* On multimode devices we may get more */
  1542. if (qmi_message_nas_get_signal_strength_output_get_strength_list (output, &array, NULL)) {
  1543. guint i;
  1544. for (i = 0; i < array->len; i++) {
  1545. QmiMessageNasGetSignalStrengthOutputStrengthListElement *element;
  1546. element = &g_array_index (array, QmiMessageNasGetSignalStrengthOutputStrengthListElement, i);
  1547. mm_dbg ("Signal strength (%s): %d dBm",
  1548. qmi_nas_radio_interface_get_string (element->radio_interface),
  1549. element->strength);
  1550. signal_max = MAX (element->strength, signal_max);
  1551. act |= mm_modem_access_technology_from_qmi_radio_interface (element->radio_interface);
  1552. }
  1553. }
  1554. /* This signal strength comes as negative dBms */
  1555. quality = STRENGTH_TO_QUALITY (signal_max);
  1556. mm_dbg ("Signal strength: %d dBm --> %u%%", signal_max, quality);
  1557. *o_quality = quality;
  1558. *o_act = act;
  1559. }
  1560. static void
  1561. get_signal_strength_ready (QmiClientNas *client,
  1562. GAsyncResult *res,
  1563. LoadSignalQualityContext *ctx)
  1564. {
  1565. QmiMessageNasGetSignalStrengthOutput *output;
  1566. GError *error = NULL;
  1567. guint8 quality = 0;
  1568. MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
  1569. output = qmi_client_nas_get_signal_strength_finish (client, res, &error);
  1570. if (!output) {
  1571. g_simple_async_result_take_error (ctx->result, error);
  1572. load_signal_quality_context_complete_and_free (ctx);
  1573. return;
  1574. }
  1575. if (!qmi_message_nas_get_signal_strength_output_get_result (output, &error)) {
  1576. qmi_message_nas_get_signal_strength_output_unref (output);
  1577. g_simple_async_result_take_error (ctx->result, error);
  1578. load_signal_quality_context_complete_and_free (ctx);
  1579. return;
  1580. }
  1581. signal_strength_get_quality_and_access_tech (ctx->self, output, &quality, &act);
  1582. /* We update the access technologies directly here when loading signal
  1583. * quality. It goes a bit out of context, but we can do it nicely */
  1584. mm_iface_modem_update_access_technologies (
  1585. MM_IFACE_MODEM (ctx->self),
  1586. act,
  1587. (MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK | MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK));
  1588. g_simple_async_result_set_op_res_gpointer (
  1589. ctx->result,
  1590. GUINT_TO_POINTER (quality),
  1591. NULL);
  1592. qmi_message_nas_get_signal_strength_output_unref (output);
  1593. load_signal_quality_context_complete_and_free (ctx);
  1594. }
  1595. static void
  1596. load_signal_quality (MMIfaceModem *self,
  1597. GAsyncReadyCallback callback,
  1598. gpointer user_data)
  1599. {
  1600. LoadSignalQualityContext *ctx;
  1601. QmiClient *client = NULL;
  1602. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1603. QMI_SERVICE_NAS, &client,
  1604. callback, user_data))
  1605. return;
  1606. ctx = g_new0 (LoadSignalQualityContext, 1);
  1607. ctx->self = g_object_ref (self);
  1608. ctx->client = g_object_ref (client);
  1609. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  1610. callback,
  1611. user_data,
  1612. load_signal_quality);
  1613. mm_dbg ("loading signal quality...");
  1614. #if defined WITH_NEWEST_QMI_COMMANDS
  1615. /* Signal info introduced in NAS 1.8 */
  1616. if (qmi_client_check_version (ctx->client, 1, 8)) {
  1617. qmi_client_nas_get_signal_info (QMI_CLIENT_NAS (ctx->client),
  1618. NULL,
  1619. 10,
  1620. NULL,
  1621. (GAsyncReadyCallback)get_signal_info_ready,
  1622. ctx);
  1623. return;
  1624. }
  1625. #endif /* WITH_NEWEST_QMI_COMMANDS */
  1626. qmi_client_nas_get_signal_strength (QMI_CLIENT_NAS (ctx->client),
  1627. NULL,
  1628. 10,
  1629. NULL,
  1630. (GAsyncReadyCallback)get_signal_strength_ready,
  1631. ctx);
  1632. }
  1633. /*****************************************************************************/
  1634. /* Powering up the modem (Modem interface) */
  1635. static gboolean
  1636. modem_power_up_down_finish (MMIfaceModem *self,
  1637. GAsyncResult *res,
  1638. GError **error)
  1639. {
  1640. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  1641. }
  1642. static void
  1643. dms_set_operating_mode_ready (QmiClientDms *client,
  1644. GAsyncResult *res,
  1645. GSimpleAsyncResult *simple)
  1646. {
  1647. QmiMessageDmsSetOperatingModeOutput *output = NULL;
  1648. GError *error = NULL;
  1649. output = qmi_client_dms_set_operating_mode_finish (client, res, &error);
  1650. if (!output) {
  1651. if (g_error_matches (error,
  1652. QMI_CORE_ERROR,
  1653. QMI_CORE_ERROR_UNSUPPORTED)) {
  1654. mm_dbg ("Device doesn't support operating mode setting. Ignoring power up/down");
  1655. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  1656. g_error_free (error);
  1657. } else {
  1658. g_prefix_error (&error, "QMI operation failed: ");
  1659. g_simple_async_result_take_error (simple, error);
  1660. }
  1661. } else if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) {
  1662. g_prefix_error (&error, "Couldn't set operating mode: ");
  1663. g_simple_async_result_take_error (simple, error);
  1664. } else {
  1665. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  1666. }
  1667. if (output)
  1668. qmi_message_dms_set_operating_mode_output_unref (output);
  1669. g_simple_async_result_complete (simple);
  1670. g_object_unref (simple);
  1671. }
  1672. static void
  1673. common_power_up_down (MMIfaceModem *self,
  1674. QmiDmsOperatingMode mode,
  1675. GAsyncReadyCallback callback,
  1676. gpointer user_data)
  1677. {
  1678. QmiMessageDmsSetOperatingModeInput *input;
  1679. GSimpleAsyncResult *result;
  1680. QmiClient *client = NULL;
  1681. GError *error = NULL;
  1682. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1683. QMI_SERVICE_DMS, &client,
  1684. callback, user_data))
  1685. return;
  1686. result = g_simple_async_result_new (G_OBJECT (self),
  1687. callback,
  1688. user_data,
  1689. common_power_up_down);
  1690. input = qmi_message_dms_set_operating_mode_input_new ();
  1691. if (!qmi_message_dms_set_operating_mode_input_set_mode (
  1692. input,
  1693. mode,
  1694. &error)) {
  1695. qmi_message_dms_set_operating_mode_input_unref (input);
  1696. g_simple_async_result_take_error (result, error);
  1697. g_simple_async_result_complete_in_idle (result);
  1698. g_object_unref (result);
  1699. return;
  1700. }
  1701. mm_dbg ("Setting device operating mode...");
  1702. qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (client),
  1703. input,
  1704. 20,
  1705. NULL,
  1706. (GAsyncReadyCallback)dms_set_operating_mode_ready,
  1707. result);
  1708. qmi_message_dms_set_operating_mode_input_unref (input);
  1709. }
  1710. static void
  1711. modem_power_down (MMIfaceModem *self,
  1712. GAsyncReadyCallback callback,
  1713. gpointer user_data)
  1714. {
  1715. common_power_up_down (self,
  1716. QMI_DMS_OPERATING_MODE_LOW_POWER,
  1717. callback,
  1718. user_data);
  1719. }
  1720. static void
  1721. modem_power_up (MMIfaceModem *self,
  1722. GAsyncReadyCallback callback,
  1723. gpointer user_data)
  1724. {
  1725. common_power_up_down (self,
  1726. QMI_DMS_OPERATING_MODE_ONLINE,
  1727. callback,
  1728. user_data);
  1729. }
  1730. /*****************************************************************************/
  1731. /* Power state loading (Modem interface) */
  1732. static MMModemPowerState
  1733. load_power_state_finish (MMIfaceModem *self,
  1734. GAsyncResult *res,
  1735. GError **error)
  1736. {
  1737. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  1738. return MM_MODEM_POWER_STATE_UNKNOWN;
  1739. return (MMModemPowerState)GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  1740. }
  1741. static void
  1742. dms_get_operating_mode_ready (QmiClientDms *client,
  1743. GAsyncResult *res,
  1744. GSimpleAsyncResult *simple)
  1745. {
  1746. QmiMessageDmsGetOperatingModeOutput *output = NULL;
  1747. GError *error = NULL;
  1748. output = qmi_client_dms_get_operating_mode_finish (client, res, &error);
  1749. if (!output) {
  1750. g_prefix_error (&error, "QMI operation failed: ");
  1751. g_simple_async_result_take_error (simple, error);
  1752. } else if (!qmi_message_dms_get_operating_mode_output_get_result (output, &error)) {
  1753. g_prefix_error (&error, "Couldn't get operating mode: ");
  1754. g_simple_async_result_take_error (simple, error);
  1755. } else {
  1756. QmiDmsOperatingMode mode = QMI_DMS_OPERATING_MODE_UNKNOWN;
  1757. qmi_message_dms_get_operating_mode_output_get_mode (output, &mode, NULL);
  1758. switch (mode) {
  1759. case QMI_DMS_OPERATING_MODE_ONLINE:
  1760. g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (MM_MODEM_POWER_STATE_ON), NULL);
  1761. break;
  1762. case QMI_DMS_OPERATING_MODE_LOW_POWER:
  1763. case QMI_DMS_OPERATING_MODE_PERSISTENT_LOW_POWER:
  1764. case QMI_DMS_OPERATING_MODE_MODE_ONLY_LOW_POWER:
  1765. g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (MM_MODEM_POWER_STATE_LOW), NULL);
  1766. break;
  1767. case QMI_DMS_OPERATING_MODE_OFFLINE:
  1768. g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (MM_MODEM_POWER_STATE_OFF), NULL);
  1769. break;
  1770. default:
  1771. g_simple_async_result_set_error (simple,
  1772. MM_CORE_ERROR,
  1773. MM_CORE_ERROR_FAILED,
  1774. "Unhandled power state: '%s' (%u)",
  1775. qmi_dms_operating_mode_get_string (mode),
  1776. mode);
  1777. break;
  1778. }
  1779. }
  1780. if (output)
  1781. qmi_message_dms_get_operating_mode_output_unref (output);
  1782. g_simple_async_result_complete (simple);
  1783. g_object_unref (simple);
  1784. }
  1785. static void
  1786. load_power_state (MMIfaceModem *self,
  1787. GAsyncReadyCallback callback,
  1788. gpointer user_data)
  1789. {
  1790. GSimpleAsyncResult *result;
  1791. QmiClient *client = NULL;
  1792. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1793. QMI_SERVICE_DMS, &client,
  1794. callback, user_data))
  1795. return;
  1796. result = g_simple_async_result_new (G_OBJECT (self),
  1797. callback,
  1798. user_data,
  1799. load_power_state);
  1800. mm_dbg ("Getting device operating mode...");
  1801. qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (client),
  1802. NULL,
  1803. 5,
  1804. NULL,
  1805. (GAsyncReadyCallback)dms_get_operating_mode_ready,
  1806. result);
  1807. }
  1808. /*****************************************************************************/
  1809. /* Create SIM (Modem interface) */
  1810. static MMSim *
  1811. create_sim_finish (MMIfaceModem *self,
  1812. GAsyncResult *res,
  1813. GError **error)
  1814. {
  1815. return mm_sim_qmi_new_finish (res, error);
  1816. }
  1817. static void
  1818. create_sim (MMIfaceModem *self,
  1819. GAsyncReadyCallback callback,
  1820. gpointer user_data)
  1821. {
  1822. /* New QMI SIM */
  1823. mm_sim_qmi_new (MM_BASE_MODEM (self),
  1824. NULL, /* cancellable */
  1825. callback,
  1826. user_data);
  1827. }
  1828. /*****************************************************************************/
  1829. /* Factory reset (Modem interface) */
  1830. static gboolean
  1831. modem_factory_reset_finish (MMIfaceModem *self,
  1832. GAsyncResult *res,
  1833. GError **error)
  1834. {
  1835. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  1836. }
  1837. static void
  1838. dms_restore_factory_defaults_ready (QmiClientDms *client,
  1839. GAsyncResult *res,
  1840. GSimpleAsyncResult *simple)
  1841. {
  1842. QmiMessageDmsRestoreFactoryDefaultsOutput *output = NULL;
  1843. GError *error = NULL;
  1844. output = qmi_client_dms_restore_factory_defaults_finish (client, res, &error);
  1845. if (!output) {
  1846. g_prefix_error (&error, "QMI operation failed: ");
  1847. g_simple_async_result_take_error (simple, error);
  1848. } else if (!qmi_message_dms_restore_factory_defaults_output_get_result (output, &error)) {
  1849. g_prefix_error (&error, "Couldn't restore factory defaults: ");
  1850. g_simple_async_result_take_error (simple, error);
  1851. } else {
  1852. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  1853. }
  1854. if (output)
  1855. qmi_message_dms_restore_factory_defaults_output_unref (output);
  1856. g_simple_async_result_complete (simple);
  1857. g_object_unref (simple);
  1858. }
  1859. static void
  1860. modem_factory_reset (MMIfaceModem *self,
  1861. const gchar *code,
  1862. GAsyncReadyCallback callback,
  1863. gpointer user_data)
  1864. {
  1865. QmiMessageDmsRestoreFactoryDefaultsInput *input;
  1866. GSimpleAsyncResult *result;
  1867. QmiClient *client = NULL;
  1868. GError *error = NULL;
  1869. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  1870. QMI_SERVICE_DMS, &client,
  1871. callback, user_data))
  1872. return;
  1873. result = g_simple_async_result_new (G_OBJECT (self),
  1874. callback,
  1875. user_data,
  1876. modem_factory_reset);
  1877. input = qmi_message_dms_restore_factory_defaults_input_new ();
  1878. if (!qmi_message_dms_restore_factory_defaults_input_set_service_programming_code (
  1879. input,
  1880. code,
  1881. &error)) {
  1882. qmi_message_dms_restore_factory_defaults_input_unref (input);
  1883. g_simple_async_result_take_error (result, error);
  1884. g_simple_async_result_complete_in_idle (result);
  1885. g_object_unref (result);
  1886. return;
  1887. }
  1888. mm_dbg ("performing a factory reset...");
  1889. qmi_client_dms_restore_factory_defaults (QMI_CLIENT_DMS (client),
  1890. input,
  1891. 10,
  1892. NULL,
  1893. (GAsyncReadyCallback)dms_restore_factory_defaults_ready,
  1894. result);
  1895. }
  1896. /*****************************************************************************/
  1897. /* Load allowed modes (Modem interface) */
  1898. typedef struct {
  1899. MMBroadbandModemQmi *self;
  1900. QmiClientNas *client;
  1901. GSimpleAsyncResult *result;
  1902. gboolean run_get_system_selection_preference;
  1903. gboolean run_get_technology_preference;
  1904. } LoadAllowedModesContext;
  1905. typedef struct {
  1906. MMModemMode allowed;
  1907. MMModemMode preferred;
  1908. } LoadAllowedModesResult;
  1909. static void
  1910. load_allowed_modes_context_complete_and_free (LoadAllowedModesContext *ctx)
  1911. {
  1912. g_simple_async_result_complete_in_idle (ctx->result);
  1913. g_object_unref (ctx->result);
  1914. g_object_unref (ctx->client);
  1915. g_object_unref (ctx->self);
  1916. g_free (ctx);
  1917. }
  1918. static gboolean
  1919. load_allowed_modes_finish (MMIfaceModem *self,
  1920. GAsyncResult *res,
  1921. MMModemMode *allowed,
  1922. MMModemMode *preferred,
  1923. GError **error)
  1924. {
  1925. LoadAllowedModesResult *result;
  1926. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  1927. return FALSE;
  1928. result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
  1929. *allowed = result->allowed;
  1930. *preferred = result->preferred;
  1931. return TRUE;
  1932. }
  1933. static void load_allowed_modes_context_step (LoadAllowedModesContext *ctx);
  1934. static void
  1935. get_technology_preference_ready (QmiClientNas *client,
  1936. GAsyncResult *res,
  1937. LoadAllowedModesContext *ctx)
  1938. {
  1939. LoadAllowedModesResult *result = NULL;
  1940. QmiMessageNasGetTechnologyPreferenceOutput *output = NULL;
  1941. GError *error = NULL;
  1942. output = qmi_client_nas_get_technology_preference_finish (client, res, &error);
  1943. if (!output) {
  1944. mm_dbg ("QMI operation failed: %s", error->message);
  1945. g_error_free (error);
  1946. } else if (!qmi_message_nas_get_technology_preference_output_get_result (output, &error)) {
  1947. mm_dbg ("Couldn't get technology preference: %s", error->message);
  1948. g_error_free (error);
  1949. } else {
  1950. MMModemMode allowed;
  1951. QmiNasRadioTechnologyPreference preference_mask;
  1952. qmi_message_nas_get_technology_preference_output_get_active (
  1953. output,
  1954. &preference_mask,
  1955. NULL, /* duration */
  1956. NULL);
  1957. allowed = mm_modem_mode_from_qmi_radio_technology_preference (preference_mask);
  1958. if (allowed == MM_MODEM_MODE_NONE) {
  1959. gchar *str;
  1960. str = qmi_nas_radio_technology_preference_build_string_from_mask (preference_mask);
  1961. mm_dbg ("Unsupported modes reported: '%s'", str);
  1962. g_free (str);
  1963. } else {
  1964. /* We got a valid value from here */
  1965. result = g_new (LoadAllowedModesResult, 1);
  1966. result->allowed = allowed;
  1967. result->preferred = MM_MODEM_MODE_NONE;
  1968. }
  1969. }
  1970. if (output)
  1971. qmi_message_nas_get_technology_preference_output_unref (output);
  1972. if (!result) {
  1973. ctx->run_get_technology_preference = FALSE;
  1974. load_allowed_modes_context_step (ctx);
  1975. return;
  1976. }
  1977. g_simple_async_result_set_op_res_gpointer (
  1978. ctx->result,
  1979. result,
  1980. (GDestroyNotify)g_free);
  1981. load_allowed_modes_context_complete_and_free (ctx);
  1982. }
  1983. static void
  1984. allowed_modes_get_system_selection_preference_ready (QmiClientNas *client,
  1985. GAsyncResult *res,
  1986. LoadAllowedModesContext *ctx)
  1987. {
  1988. LoadAllowedModesResult *result = NULL;
  1989. QmiMessageNasGetSystemSelectionPreferenceOutput *output = NULL;
  1990. GError *error = NULL;
  1991. QmiNasRatModePreference mode_preference_mask = 0;
  1992. output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error);
  1993. if (!output) {
  1994. mm_dbg ("QMI operation failed: %s", error->message);
  1995. g_error_free (error);
  1996. } else if (!qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) {
  1997. mm_dbg ("Couldn't get system selection preference: %s", error->message);
  1998. g_error_free (error);
  1999. } else if (!qmi_message_nas_get_system_selection_preference_output_get_mode_preference (
  2000. output,
  2001. &mode_preference_mask,
  2002. NULL)) {
  2003. mm_dbg ("Mode preference not reported in system selection preference");
  2004. } else {
  2005. MMModemMode allowed;
  2006. allowed = mm_modem_mode_from_qmi_rat_mode_preference (mode_preference_mask);
  2007. if (allowed == MM_MODEM_MODE_NONE) {
  2008. gchar *str;
  2009. str = qmi_nas_rat_mode_preference_build_string_from_mask (mode_preference_mask);
  2010. mm_dbg ("Unsupported modes reported: '%s'", str);
  2011. g_free (str);
  2012. } else {
  2013. QmiNasGsmWcdmaAcquisitionOrderPreference gsm_or_wcdma;
  2014. /* We got a valid value from here */
  2015. result = g_new (LoadAllowedModesResult, 1);
  2016. result->allowed = allowed;
  2017. result->preferred = MM_MODEM_MODE_NONE;
  2018. if ((mode_preference_mask & QMI_NAS_RAT_MODE_PREFERENCE_GSM) &&
  2019. (mode_preference_mask & QMI_NAS_RAT_MODE_PREFERENCE_UMTS) &&
  2020. qmi_message_nas_get_system_selection_preference_output_get_gsm_wcdma_acquisition_order_preference (
  2021. output,
  2022. &gsm_or_wcdma,
  2023. NULL)) {
  2024. result->preferred = mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (gsm_or_wcdma);
  2025. }
  2026. }
  2027. }
  2028. if (output)
  2029. qmi_message_nas_get_system_selection_preference_output_unref (output);
  2030. if (!result) {
  2031. /* Try with the deprecated command */
  2032. ctx->run_get_system_selection_preference = FALSE;
  2033. load_allowed_modes_context_step (ctx);
  2034. return;
  2035. }
  2036. g_simple_async_result_set_op_res_gpointer (
  2037. ctx->result,
  2038. result,
  2039. (GDestroyNotify)g_free);
  2040. load_allowed_modes_context_complete_and_free (ctx);
  2041. }
  2042. static void
  2043. load_allowed_modes_context_step (LoadAllowedModesContext *ctx)
  2044. {
  2045. if (ctx->run_get_system_selection_preference) {
  2046. qmi_client_nas_get_system_selection_preference (
  2047. ctx->client,
  2048. NULL, /* no input */
  2049. 5,
  2050. NULL, /* cancellable */
  2051. (GAsyncReadyCallback)allowed_modes_get_system_selection_preference_ready,
  2052. ctx);
  2053. return;
  2054. }
  2055. if (ctx->run_get_technology_preference) {
  2056. qmi_client_nas_get_technology_preference (
  2057. ctx->client,
  2058. NULL, /* no input */
  2059. 5,
  2060. NULL, /* cancellable */
  2061. (GAsyncReadyCallback)get_technology_preference_ready,
  2062. ctx);
  2063. return;
  2064. }
  2065. g_simple_async_result_set_error (
  2066. ctx->result,
  2067. MM_CORE_ERROR,
  2068. MM_CORE_ERROR_UNSUPPORTED,
  2069. "Loading allowed modes is not supported by this device");
  2070. load_allowed_modes_context_complete_and_free (ctx);
  2071. }
  2072. static void
  2073. load_allowed_modes (MMIfaceModem *self,
  2074. GAsyncReadyCallback callback,
  2075. gpointer user_data)
  2076. {
  2077. LoadAllowedModesContext *ctx;
  2078. QmiClient *client = NULL;
  2079. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  2080. QMI_SERVICE_NAS, &client,
  2081. callback, user_data))
  2082. return;
  2083. ctx = g_new0 (LoadAllowedModesContext, 1);
  2084. ctx->self = g_object_ref (self);
  2085. ctx->client = g_object_ref (client);
  2086. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  2087. callback,
  2088. user_data,
  2089. load_allowed_modes);
  2090. /* System selection preference introduced in NAS 1.1 */
  2091. ctx->run_get_system_selection_preference = qmi_client_check_version (client, 1, 1);
  2092. /* Technology preference introduced in NAS 1.0, so always available */
  2093. ctx->run_get_technology_preference = TRUE;
  2094. load_allowed_modes_context_step (ctx);
  2095. }
  2096. /*****************************************************************************/
  2097. /* Set allowed modes (Modem interface) */
  2098. typedef struct {
  2099. MMBroadbandModemQmi *self;
  2100. QmiClientNas *client;
  2101. GSimpleAsyncResult *result;
  2102. MMModemMode allowed;
  2103. MMModemMode preferred;
  2104. gboolean run_set_system_selection_preference;
  2105. gboolean run_set_technology_preference;
  2106. } SetAllowedModesContext;
  2107. static void
  2108. set_allowed_modes_context_complete_and_free (SetAllowedModesContext *ctx)
  2109. {
  2110. g_simple_async_result_complete_in_idle (ctx->result);
  2111. g_object_unref (ctx->result);
  2112. g_object_unref (ctx->client);
  2113. g_object_unref (ctx->self);
  2114. g_free (ctx);
  2115. }
  2116. static gboolean
  2117. set_allowed_modes_finish (MMIfaceModem *self,
  2118. GAsyncResult *res,
  2119. GError **error)
  2120. {
  2121. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  2122. }
  2123. static void set_allowed_modes_context_step (SetAllowedModesContext *ctx);
  2124. static void
  2125. set_technology_preference_ready (QmiClientNas *client,
  2126. GAsyncResult *res,
  2127. SetAllowedModesContext *ctx)
  2128. {
  2129. QmiMessageNasSetTechnologyPreferenceOutput *output = NULL;
  2130. GError *error = NULL;
  2131. output = qmi_client_nas_set_technology_preference_finish (client, res, &error);
  2132. if (!output) {
  2133. mm_dbg ("QMI operation failed: %s", error->message);
  2134. g_error_free (error);
  2135. } else if (!qmi_message_nas_set_technology_preference_output_get_result (output, &error) &&
  2136. !g_error_matches (error,
  2137. QMI_PROTOCOL_ERROR,
  2138. QMI_PROTOCOL_ERROR_NO_EFFECT)) {
  2139. mm_dbg ("Couldn't set technology preference: %s", error->message);
  2140. g_error_free (error);
  2141. qmi_message_nas_set_technology_preference_output_unref (output);
  2142. } else {
  2143. if (error)
  2144. g_error_free (error);
  2145. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  2146. set_allowed_modes_context_complete_and_free (ctx);
  2147. qmi_message_nas_set_technology_preference_output_unref (output);
  2148. return;
  2149. }
  2150. ctx->run_set_technology_preference = FALSE;
  2151. set_allowed_modes_context_step (ctx);
  2152. }
  2153. static void
  2154. allowed_modes_set_system_selection_preference_ready (QmiClientNas *client,
  2155. GAsyncResult *res,
  2156. SetAllowedModesContext *ctx)
  2157. {
  2158. QmiMessageNasSetSystemSelectionPreferenceOutput *output = NULL;
  2159. GError *error = NULL;
  2160. output = qmi_client_nas_set_system_selection_preference_finish (client, res, &error);
  2161. if (!output) {
  2162. mm_dbg ("QMI operation failed: %s", error->message);
  2163. g_error_free (error);
  2164. } else if (!qmi_message_nas_set_system_selection_preference_output_get_result (output, &error)) {
  2165. mm_dbg ("Couldn't set system selection preference: %s", error->message);
  2166. g_error_free (error);
  2167. qmi_message_nas_set_system_selection_preference_output_unref (output);
  2168. } else {
  2169. /* Good! TODO: do we really need to wait for the indication? */
  2170. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  2171. set_allowed_modes_context_complete_and_free (ctx);
  2172. qmi_message_nas_set_system_selection_preference_output_unref (output);
  2173. return;
  2174. }
  2175. /* Try with the deprecated command */
  2176. ctx->run_set_system_selection_preference = FALSE;
  2177. set_allowed_modes_context_step (ctx);
  2178. }
  2179. static void
  2180. set_allowed_modes_context_step (SetAllowedModesContext *ctx)
  2181. {
  2182. if (ctx->run_set_system_selection_preference) {
  2183. QmiMessageNasSetSystemSelectionPreferenceInput *input;
  2184. QmiNasRatModePreference pref;
  2185. pref = mm_modem_mode_to_qmi_rat_mode_preference (ctx->allowed,
  2186. mm_iface_modem_is_cdma (MM_IFACE_MODEM (ctx->self)),
  2187. mm_iface_modem_is_3gpp (MM_IFACE_MODEM (ctx->self)));
  2188. if (!pref) {
  2189. gchar *str;
  2190. str = mm_modem_mode_build_string_from_mask (ctx->allowed);
  2191. g_simple_async_result_set_error (ctx->result,
  2192. MM_CORE_ERROR,
  2193. MM_CORE_ERROR_FAILED,
  2194. "Unhandled allowed mode setting: '%s'",
  2195. str);
  2196. g_free (str);
  2197. set_allowed_modes_context_complete_and_free (ctx);
  2198. return;
  2199. }
  2200. input = qmi_message_nas_set_system_selection_preference_input_new ();
  2201. qmi_message_nas_set_system_selection_preference_input_set_mode_preference (input, pref, NULL);
  2202. /* Only set acquisition order preference if both 2G and 3G given as allowed */
  2203. if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (ctx->self)) &&
  2204. (ctx->allowed & (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G))) {
  2205. QmiNasGsmWcdmaAcquisitionOrderPreference order;
  2206. order = mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (ctx->preferred);
  2207. qmi_message_nas_set_system_selection_preference_input_set_gsm_wcdma_acquisition_order_preference (input, order, NULL);
  2208. }
  2209. qmi_message_nas_set_system_selection_preference_input_set_change_duration (input, QMI_NAS_CHANGE_DURATION_PERMANENT, NULL);
  2210. qmi_client_nas_set_system_selection_preference (
  2211. ctx->client,
  2212. input,
  2213. 5,
  2214. NULL, /* cancellable */
  2215. (GAsyncReadyCallback)allowed_modes_set_system_selection_preference_ready,
  2216. ctx);
  2217. qmi_message_nas_set_system_selection_preference_input_unref (input);
  2218. return;
  2219. }
  2220. if (ctx->run_set_technology_preference) {
  2221. QmiMessageNasSetTechnologyPreferenceInput *input;
  2222. QmiNasRadioTechnologyPreference pref;
  2223. if (ctx->preferred != MM_MODEM_MODE_NONE) {
  2224. g_simple_async_result_set_error (ctx->result,
  2225. MM_CORE_ERROR,
  2226. MM_CORE_ERROR_FAILED,
  2227. "Cannot set specific preferred mode");
  2228. set_allowed_modes_context_complete_and_free (ctx);
  2229. return;
  2230. }
  2231. pref = mm_modem_mode_to_qmi_radio_technology_preference (ctx->allowed,
  2232. mm_iface_modem_is_cdma (MM_IFACE_MODEM (ctx->self)));
  2233. if (!pref) {
  2234. gchar *str;
  2235. str = mm_modem_mode_build_string_from_mask (ctx->allowed);
  2236. g_simple_async_result_set_error (ctx->result,
  2237. MM_CORE_ERROR,
  2238. MM_CORE_ERROR_FAILED,
  2239. "Unhandled allowed mode setting: '%s'",
  2240. str);
  2241. g_free (str);
  2242. set_allowed_modes_context_complete_and_free (ctx);
  2243. return;
  2244. }
  2245. input = qmi_message_nas_set_technology_preference_input_new ();
  2246. qmi_message_nas_set_technology_preference_input_set_current (input, pref, QMI_NAS_PREFERENCE_DURATION_PERMANENT, NULL);
  2247. qmi_client_nas_set_technology_preference (
  2248. ctx->client,
  2249. input,
  2250. 5,
  2251. NULL, /* cancellable */
  2252. (GAsyncReadyCallback)set_technology_preference_ready,
  2253. ctx);
  2254. qmi_message_nas_set_technology_preference_input_unref (input);
  2255. return;
  2256. }
  2257. g_simple_async_result_set_error (
  2258. ctx->result,
  2259. MM_CORE_ERROR,
  2260. MM_CORE_ERROR_UNSUPPORTED,
  2261. "Setting allowed modes is not supported by this device");
  2262. set_allowed_modes_context_complete_and_free (ctx);
  2263. }
  2264. static void
  2265. set_allowed_modes (MMIfaceModem *self,
  2266. MMModemMode allowed,
  2267. MMModemMode preferred,
  2268. GAsyncReadyCallback callback,
  2269. gpointer user_data)
  2270. {
  2271. SetAllowedModesContext *ctx;
  2272. QmiClient *client = NULL;
  2273. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  2274. QMI_SERVICE_NAS, &client,
  2275. callback, user_data))
  2276. return;
  2277. ctx = g_new0 (SetAllowedModesContext, 1);
  2278. ctx->self = g_object_ref (self);
  2279. ctx->client = g_object_ref (client);
  2280. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  2281. callback,
  2282. user_data,
  2283. set_allowed_modes);
  2284. ctx->allowed = allowed;
  2285. ctx->preferred = preferred;
  2286. /* System selection preference introduced in NAS 1.1 */
  2287. ctx->run_set_system_selection_preference = qmi_client_check_version (client, 1, 1);
  2288. /* Technology preference introduced in NAS 1.0, so always available */
  2289. ctx->run_set_technology_preference = TRUE;
  2290. set_allowed_modes_context_step (ctx);
  2291. }
  2292. /*****************************************************************************/
  2293. /* IMEI loading (3GPP interface) */
  2294. static gchar *
  2295. modem_3gpp_load_imei_finish (MMIfaceModem3gpp *self,
  2296. GAsyncResult *res,
  2297. GError **error)
  2298. {
  2299. gchar *imei;
  2300. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  2301. return NULL;
  2302. imei = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  2303. mm_dbg ("loaded IMEI: %s", imei);
  2304. return imei;
  2305. }
  2306. static void
  2307. modem_3gpp_load_imei (MMIfaceModem3gpp *_self,
  2308. GAsyncReadyCallback callback,
  2309. gpointer user_data)
  2310. {
  2311. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  2312. GSimpleAsyncResult *result;
  2313. result = g_simple_async_result_new (G_OBJECT (self),
  2314. callback,
  2315. user_data,
  2316. modem_3gpp_load_imei);
  2317. if (self->priv->imei)
  2318. g_simple_async_result_set_op_res_gpointer (result,
  2319. self->priv->imei,
  2320. NULL);
  2321. else
  2322. g_simple_async_result_set_error (result,
  2323. MM_CORE_ERROR,
  2324. MM_CORE_ERROR_FAILED,
  2325. "Device doesn't report a valid IMEI");
  2326. g_simple_async_result_complete_in_idle (result);
  2327. g_object_unref (result);
  2328. }
  2329. /*****************************************************************************/
  2330. /* Facility locks status loading (3GPP interface) */
  2331. typedef struct {
  2332. MMBroadbandModem *self;
  2333. GSimpleAsyncResult *result;
  2334. QmiClient *client;
  2335. guint current;
  2336. MMModem3gppFacility facilities;
  2337. MMModem3gppFacility locks;
  2338. } LoadEnabledFacilityLocksContext;
  2339. static void get_next_facility_lock_status (LoadEnabledFacilityLocksContext *ctx);
  2340. static void
  2341. load_enabled_facility_locks_context_complete_and_free (LoadEnabledFacilityLocksContext *ctx)
  2342. {
  2343. g_simple_async_result_complete (ctx->result);
  2344. g_object_unref (ctx->result);
  2345. g_object_unref (ctx->client);
  2346. g_object_unref (ctx->self);
  2347. g_free (ctx);
  2348. }
  2349. static MMModem3gppFacility
  2350. modem_3gpp_load_enabled_facility_locks_finish (MMIfaceModem3gpp *self,
  2351. GAsyncResult *res,
  2352. GError **error)
  2353. {
  2354. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  2355. return MM_MODEM_3GPP_FACILITY_NONE;
  2356. return ((MMModem3gppFacility) GPOINTER_TO_UINT (
  2357. g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
  2358. }
  2359. static void
  2360. dms_uim_get_ck_status_ready (QmiClientDms *client,
  2361. GAsyncResult *res,
  2362. LoadEnabledFacilityLocksContext *ctx)
  2363. {
  2364. gchar *facility_str;
  2365. QmiMessageDmsUimGetCkStatusOutput *output;
  2366. facility_str = mm_modem_3gpp_facility_build_string_from_mask (1 << ctx->current);
  2367. output = qmi_client_dms_uim_get_ck_status_finish (client, res, NULL);
  2368. if (!output ||
  2369. !qmi_message_dms_uim_get_ck_status_output_get_result (output, NULL)) {
  2370. /* On errors, we'll just assume disabled */
  2371. mm_dbg ("Couldn't query facility '%s' status, assuming disabled", facility_str);
  2372. ctx->locks &= ~(1 << ctx->current);
  2373. } else {
  2374. QmiDmsUimFacilityState state;
  2375. guint8 verify_retries_left;
  2376. guint8 unblock_retries_left;
  2377. qmi_message_dms_uim_get_ck_status_output_get_ck_status (
  2378. output,
  2379. &state,
  2380. &verify_retries_left,
  2381. &unblock_retries_left,
  2382. NULL);
  2383. mm_dbg ("Facility '%s' is: '%s'",
  2384. facility_str,
  2385. qmi_dms_uim_facility_state_get_string (state));
  2386. if (state == QMI_DMS_UIM_FACILITY_STATE_ACTIVATED ||
  2387. state == QMI_DMS_UIM_FACILITY_STATE_BLOCKED) {
  2388. ctx->locks |= (1 << ctx->current);
  2389. }
  2390. }
  2391. if (output)
  2392. qmi_message_dms_uim_get_ck_status_output_unref (output);
  2393. g_free (facility_str);
  2394. /* And go on with the next one */
  2395. ctx->current++;
  2396. get_next_facility_lock_status (ctx);
  2397. }
  2398. static void
  2399. get_next_facility_lock_status (LoadEnabledFacilityLocksContext *ctx)
  2400. {
  2401. guint i;
  2402. for (i = ctx->current; i < sizeof (MMModem3gppFacility) * 8; i++) {
  2403. guint32 facility = 1 << i;
  2404. /* Found the next one to query! */
  2405. if (ctx->facilities & facility) {
  2406. QmiMessageDmsUimGetCkStatusInput *input;
  2407. /* Keep the current one */
  2408. ctx->current = i;
  2409. /* Query current */
  2410. input = qmi_message_dms_uim_get_ck_status_input_new ();
  2411. qmi_message_dms_uim_get_ck_status_input_set_facility (
  2412. input,
  2413. mm_3gpp_facility_to_qmi_uim_facility (facility),
  2414. NULL);
  2415. qmi_client_dms_uim_get_ck_status (QMI_CLIENT_DMS (ctx->client),
  2416. input,
  2417. 5,
  2418. NULL,
  2419. (GAsyncReadyCallback)dms_uim_get_ck_status_ready,
  2420. ctx);
  2421. qmi_message_dms_uim_get_ck_status_input_unref (input);
  2422. return;
  2423. }
  2424. }
  2425. /* No more facilities to query, all done */
  2426. g_simple_async_result_set_op_res_gpointer (ctx->result,
  2427. GUINT_TO_POINTER (ctx->locks),
  2428. NULL);
  2429. load_enabled_facility_locks_context_complete_and_free (ctx);
  2430. }
  2431. static void
  2432. modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self,
  2433. GAsyncReadyCallback callback,
  2434. gpointer user_data)
  2435. {
  2436. LoadEnabledFacilityLocksContext *ctx;
  2437. QmiClient *client = NULL;
  2438. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  2439. QMI_SERVICE_DMS, &client,
  2440. callback, user_data))
  2441. return;
  2442. ctx = g_new (LoadEnabledFacilityLocksContext, 1);
  2443. ctx->self = g_object_ref (self);
  2444. ctx->client = g_object_ref (client);
  2445. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  2446. callback,
  2447. user_data,
  2448. modem_3gpp_load_enabled_facility_locks);
  2449. /* Set initial list of facilities to query */
  2450. ctx->facilities = (MM_MODEM_3GPP_FACILITY_PH_SIM |
  2451. MM_MODEM_3GPP_FACILITY_NET_PERS |
  2452. MM_MODEM_3GPP_FACILITY_NET_SUB_PERS |
  2453. MM_MODEM_3GPP_FACILITY_PROVIDER_PERS |
  2454. MM_MODEM_3GPP_FACILITY_CORP_PERS);
  2455. ctx->locks = MM_MODEM_3GPP_FACILITY_NONE;
  2456. ctx->current = 0;
  2457. get_next_facility_lock_status (ctx);
  2458. }
  2459. /*****************************************************************************/
  2460. /* Scan networks (3GPP interface) */
  2461. static GList *
  2462. modem_3gpp_scan_networks_finish (MMIfaceModem3gpp *self,
  2463. GAsyncResult *res,
  2464. GError **error)
  2465. {
  2466. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  2467. return NULL;
  2468. /* We return the GList as it is */
  2469. return (GList *) g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
  2470. }
  2471. static MMModem3gppNetworkAvailability
  2472. network_availability_from_qmi_nas_network_status (QmiNasNetworkStatus qmi)
  2473. {
  2474. if (qmi & QMI_NAS_NETWORK_STATUS_CURRENT_SERVING)
  2475. return MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT;
  2476. if (qmi & QMI_NAS_NETWORK_STATUS_AVAILABLE) {
  2477. if (qmi & QMI_NAS_NETWORK_STATUS_FORBIDDEN)
  2478. return MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN;
  2479. return MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE;
  2480. }
  2481. return MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN;
  2482. }
  2483. static MM3gppNetworkInfo *
  2484. get_3gpp_network_info (QmiMessageNasNetworkScanOutputNetworkInformationElement *element)
  2485. {
  2486. GString *aux;
  2487. MM3gppNetworkInfo *info;
  2488. info = g_new (MM3gppNetworkInfo, 1);
  2489. info->status = network_availability_from_qmi_nas_network_status (element->network_status);
  2490. aux = g_string_new ("");
  2491. /* MCC always 3 digits */
  2492. g_string_append_printf (aux, "%.3"G_GUINT16_FORMAT, element->mcc);
  2493. /* Guess about MNC, if < 100 assume it's 2 digits, no PCS info here */
  2494. if (element->mnc >= 100)
  2495. g_string_append_printf (aux, "%.3"G_GUINT16_FORMAT, element->mnc);
  2496. else
  2497. g_string_append_printf (aux, "%.2"G_GUINT16_FORMAT, element->mnc);
  2498. info->operator_code = g_string_free (aux, FALSE);
  2499. info->operator_short = NULL;
  2500. info->operator_long = g_strdup (element->description);
  2501. info->access_tech = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
  2502. return info;
  2503. }
  2504. static MMModemAccessTechnology
  2505. get_3gpp_access_technology (GArray *array,
  2506. gboolean *array_used_flags,
  2507. guint16 mcc,
  2508. guint16 mnc)
  2509. {
  2510. guint i;
  2511. for (i = 0; i < array->len; i++) {
  2512. QmiMessageNasNetworkScanOutputRadioAccessTechnologyElement *element;
  2513. if (array_used_flags[i])
  2514. continue;
  2515. element = &g_array_index (array, QmiMessageNasNetworkScanOutputRadioAccessTechnologyElement, i);
  2516. if (element->mcc == mcc &&
  2517. element->mnc == mnc) {
  2518. array_used_flags[i] = TRUE;
  2519. return mm_modem_access_technology_from_qmi_radio_interface (element->radio_interface);
  2520. }
  2521. }
  2522. return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
  2523. }
  2524. static void
  2525. nas_network_scan_ready (QmiClientNas *client,
  2526. GAsyncResult *res,
  2527. GSimpleAsyncResult *simple)
  2528. {
  2529. QmiMessageNasNetworkScanOutput *output = NULL;
  2530. GError *error = NULL;
  2531. output = qmi_client_nas_network_scan_finish (client, res, &error);
  2532. if (!output) {
  2533. g_prefix_error (&error, "QMI operation failed: ");
  2534. g_simple_async_result_take_error (simple, error);
  2535. } else if (!qmi_message_nas_network_scan_output_get_result (output, &error)) {
  2536. g_prefix_error (&error, "Couldn't scan networks: ");
  2537. g_simple_async_result_take_error (simple, error);
  2538. } else {
  2539. GList *scan_result = NULL;
  2540. GArray *info_array = NULL;
  2541. if (qmi_message_nas_network_scan_output_get_network_information (output, &info_array, NULL)) {
  2542. GArray *rat_array = NULL;
  2543. gboolean *rat_array_used_flags = NULL;
  2544. guint i;
  2545. /* Get optional RAT array */
  2546. qmi_message_nas_network_scan_output_get_radio_access_technology (output, &rat_array, NULL);
  2547. if (rat_array)
  2548. rat_array_used_flags = g_new0 (gboolean, rat_array->len);
  2549. for (i = 0; i < info_array->len; i++) {
  2550. QmiMessageNasNetworkScanOutputNetworkInformationElement *info_element;
  2551. MM3gppNetworkInfo *info;
  2552. info_element = &g_array_index (info_array, QmiMessageNasNetworkScanOutputNetworkInformationElement, i);
  2553. info = get_3gpp_network_info (info_element);
  2554. if (rat_array)
  2555. info->access_tech = get_3gpp_access_technology (rat_array,
  2556. rat_array_used_flags,
  2557. info_element->mcc,
  2558. info_element->mnc);
  2559. scan_result = g_list_append (scan_result, info);
  2560. }
  2561. g_free (rat_array_used_flags);
  2562. }
  2563. /* We *require* a callback in the async method, as we're not setting a
  2564. * GDestroyNotify callback */
  2565. g_simple_async_result_set_op_res_gpointer (simple, scan_result, NULL);
  2566. }
  2567. if (output)
  2568. qmi_message_nas_network_scan_output_unref (output);
  2569. g_simple_async_result_complete (simple);
  2570. g_object_unref (simple);
  2571. }
  2572. static void
  2573. modem_3gpp_scan_networks (MMIfaceModem3gpp *self,
  2574. GAsyncReadyCallback callback,
  2575. gpointer user_data)
  2576. {
  2577. GSimpleAsyncResult *result;
  2578. QmiClient *client = NULL;
  2579. /* We will pass the GList in the GSimpleAsyncResult, so we must
  2580. * ensure that there is a callback so that we get it properly
  2581. * passed to the caller and deallocated afterwards */
  2582. g_assert (callback != NULL);
  2583. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  2584. QMI_SERVICE_NAS, &client,
  2585. callback, user_data))
  2586. return;
  2587. result = g_simple_async_result_new (G_OBJECT (self),
  2588. callback,
  2589. user_data,
  2590. modem_3gpp_scan_networks);
  2591. mm_dbg ("Scanning networks...");
  2592. qmi_client_nas_network_scan (QMI_CLIENT_NAS (client),
  2593. NULL,
  2594. 100,
  2595. NULL,
  2596. (GAsyncReadyCallback)nas_network_scan_ready,
  2597. result);
  2598. }
  2599. /*****************************************************************************/
  2600. /* Load operator name (3GPP interface) */
  2601. static gchar *
  2602. modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *_self,
  2603. GAsyncResult *res,
  2604. GError **error)
  2605. {
  2606. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  2607. if (self->priv->current_operator_description)
  2608. return g_strdup (self->priv->current_operator_description);
  2609. g_set_error (error,
  2610. MM_CORE_ERROR,
  2611. MM_CORE_ERROR_FAILED,
  2612. "Current operator description is still unknown");
  2613. return NULL;
  2614. }
  2615. static void
  2616. modem_3gpp_load_operator_name (MMIfaceModem3gpp *self,
  2617. GAsyncReadyCallback callback,
  2618. gpointer user_data)
  2619. {
  2620. GSimpleAsyncResult *result;
  2621. /* Just finish the async operation */
  2622. result = g_simple_async_result_new (G_OBJECT (self),
  2623. callback,
  2624. user_data,
  2625. modem_3gpp_load_operator_name);
  2626. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  2627. g_simple_async_result_complete_in_idle (result);
  2628. g_object_unref (result);
  2629. }
  2630. /*****************************************************************************/
  2631. /* Load operator code (3GPP interface) */
  2632. static gchar *
  2633. modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *_self,
  2634. GAsyncResult *res,
  2635. GError **error)
  2636. {
  2637. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  2638. if (self->priv->current_operator_id)
  2639. return g_strdup (self->priv->current_operator_id);
  2640. g_set_error (error,
  2641. MM_CORE_ERROR,
  2642. MM_CORE_ERROR_FAILED,
  2643. "Current operator MCC/MNC is still unknown");
  2644. return NULL;
  2645. }
  2646. static void
  2647. modem_3gpp_load_operator_code (MMIfaceModem3gpp *self,
  2648. GAsyncReadyCallback callback,
  2649. gpointer user_data)
  2650. {
  2651. GSimpleAsyncResult *result;
  2652. /* Just finish the async operation */
  2653. result = g_simple_async_result_new (G_OBJECT (self),
  2654. callback,
  2655. user_data,
  2656. modem_3gpp_load_operator_code);
  2657. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  2658. g_simple_async_result_complete_in_idle (result);
  2659. g_object_unref (result);
  2660. }
  2661. /*****************************************************************************/
  2662. /* Register in network (3GPP interface) */
  2663. static gboolean
  2664. modem_3gpp_register_in_network_finish (MMIfaceModem3gpp *self,
  2665. GAsyncResult *res,
  2666. GError **error)
  2667. {
  2668. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  2669. }
  2670. static void
  2671. initiate_network_register_ready (QmiClientNas *client,
  2672. GAsyncResult *res,
  2673. GSimpleAsyncResult *simple)
  2674. {
  2675. GError *error = NULL;
  2676. QmiMessageNasInitiateNetworkRegisterOutput *output;
  2677. output = qmi_client_nas_initiate_network_register_finish (client, res, &error);
  2678. if (!output) {
  2679. g_prefix_error (&error, "QMI operation failed: ");
  2680. g_simple_async_result_take_error (simple, error);
  2681. } else if (!qmi_message_nas_initiate_network_register_output_get_result (output, &error)) {
  2682. /* NOFX is not an error, they actually play pretty well */
  2683. if (g_error_matches (error,
  2684. QMI_PROTOCOL_ERROR,
  2685. QMI_PROTOCOL_ERROR_NO_EFFECT)) {
  2686. g_error_free (error);
  2687. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  2688. } else {
  2689. g_prefix_error (&error, "Couldn't initiate network register: ");
  2690. g_simple_async_result_take_error (simple, error);
  2691. }
  2692. } else
  2693. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  2694. if (output)
  2695. qmi_message_nas_initiate_network_register_output_unref (output);
  2696. g_simple_async_result_complete (simple);
  2697. g_object_unref (simple);
  2698. }
  2699. static void
  2700. modem_3gpp_register_in_network (MMIfaceModem3gpp *self,
  2701. const gchar *operator_id,
  2702. GCancellable *cancellable,
  2703. GAsyncReadyCallback callback,
  2704. gpointer user_data)
  2705. {
  2706. guint16 mcc = 0;
  2707. guint16 mnc = 0;
  2708. QmiClient *client = NULL;
  2709. QmiMessageNasInitiateNetworkRegisterInput *input;
  2710. GError *error = NULL;
  2711. /* Parse input MCC/MNC */
  2712. if (operator_id && !mm_3gpp_parse_operator_id (operator_id, &mcc, &mnc, &error)) {
  2713. g_assert (error != NULL);
  2714. g_simple_async_report_take_gerror_in_idle (G_OBJECT (self),
  2715. callback,
  2716. user_data,
  2717. error);
  2718. return;
  2719. }
  2720. /* Get NAS client */
  2721. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  2722. QMI_SERVICE_NAS, &client,
  2723. callback, user_data))
  2724. return;
  2725. input = qmi_message_nas_initiate_network_register_input_new ();
  2726. if (mcc) {
  2727. /* If the user sent a specific network to use, lock it in. */
  2728. qmi_message_nas_initiate_network_register_input_set_action (
  2729. input,
  2730. QMI_NAS_NETWORK_REGISTER_TYPE_MANUAL,
  2731. NULL);
  2732. qmi_message_nas_initiate_network_register_input_set_manual_registration_info_3gpp (
  2733. input,
  2734. mcc,
  2735. mnc,
  2736. QMI_NAS_RADIO_INTERFACE_UNKNOWN,
  2737. NULL);
  2738. } else {
  2739. /* Otherwise, automatic registration */
  2740. qmi_message_nas_initiate_network_register_input_set_action (
  2741. input,
  2742. QMI_NAS_NETWORK_REGISTER_TYPE_AUTOMATIC,
  2743. NULL);
  2744. }
  2745. qmi_client_nas_initiate_network_register (
  2746. QMI_CLIENT_NAS (client),
  2747. input,
  2748. 120,
  2749. cancellable,
  2750. (GAsyncReadyCallback)initiate_network_register_ready,
  2751. g_simple_async_result_new (G_OBJECT (self),
  2752. callback,
  2753. user_data,
  2754. modem_3gpp_register_in_network));
  2755. qmi_message_nas_initiate_network_register_input_unref (input);
  2756. }
  2757. /*****************************************************************************/
  2758. /* Registration checks (3GPP interface) */
  2759. typedef struct {
  2760. MMBroadbandModemQmi *self;
  2761. QmiClientNas *client;
  2762. GSimpleAsyncResult *result;
  2763. } Run3gppRegistrationChecksContext;
  2764. static void
  2765. run_3gpp_registration_checks_context_complete_and_free (Run3gppRegistrationChecksContext *ctx)
  2766. {
  2767. g_simple_async_result_complete (ctx->result);
  2768. g_object_unref (ctx->result);
  2769. g_object_unref (ctx->client);
  2770. g_object_unref (ctx->self);
  2771. g_free (ctx);
  2772. }
  2773. static gboolean
  2774. modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self,
  2775. GAsyncResult *res,
  2776. GError **error)
  2777. {
  2778. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  2779. }
  2780. static void
  2781. common_process_serving_system_3gpp (MMBroadbandModemQmi *self,
  2782. QmiMessageNasGetServingSystemOutput *response_output,
  2783. QmiIndicationNasServingSystemOutput *indication_output)
  2784. {
  2785. QmiNasRegistrationState registration_state;
  2786. QmiNasAttachState cs_attach_state;
  2787. QmiNasAttachState ps_attach_state;
  2788. QmiNasNetworkType selected_network;
  2789. GArray *radio_interfaces;
  2790. GArray *data_service_capabilities;
  2791. QmiNasRoamingIndicatorStatus roaming;
  2792. guint16 mcc;
  2793. guint16 mnc;
  2794. const gchar *description;
  2795. gboolean has_pcs_digit;
  2796. guint16 lac;
  2797. guint32 cid;
  2798. MMModemAccessTechnology mm_access_technologies;
  2799. MMModem3gppRegistrationState mm_cs_registration_state;
  2800. MMModem3gppRegistrationState mm_ps_registration_state;
  2801. if (response_output)
  2802. qmi_message_nas_get_serving_system_output_get_serving_system (
  2803. response_output,
  2804. &registration_state,
  2805. &cs_attach_state,
  2806. &ps_attach_state,
  2807. &selected_network,
  2808. &radio_interfaces,
  2809. NULL);
  2810. else
  2811. qmi_indication_nas_serving_system_output_get_serving_system (
  2812. indication_output,
  2813. &registration_state,
  2814. &cs_attach_state,
  2815. &ps_attach_state,
  2816. &selected_network,
  2817. &radio_interfaces,
  2818. NULL);
  2819. /* Build access technologies mask */
  2820. data_service_capabilities = NULL;
  2821. if (response_output)
  2822. qmi_message_nas_get_serving_system_output_get_data_service_capability (response_output, &data_service_capabilities, NULL);
  2823. else
  2824. qmi_indication_nas_serving_system_output_get_data_service_capability (indication_output, &data_service_capabilities, NULL);
  2825. if (data_service_capabilities)
  2826. mm_access_technologies =
  2827. mm_modem_access_technologies_from_qmi_data_capability_array (data_service_capabilities);
  2828. else
  2829. mm_access_technologies =
  2830. mm_modem_access_technologies_from_qmi_radio_interface_array (radio_interfaces);
  2831. /* Only process 3GPP info.
  2832. * Seen the case already where 'selected_network' gives UNKNOWN but we still
  2833. * have valid LTE info around. */
  2834. if (selected_network == QMI_NAS_NETWORK_TYPE_3GPP ||
  2835. (selected_network == QMI_NAS_NETWORK_TYPE_UNKNOWN &&
  2836. (mm_access_technologies & MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK))) {
  2837. mm_dbg ("Processing 3GPP info...");
  2838. } else {
  2839. MMModem3gppRegistrationState reg_state_3gpp;
  2840. mm_dbg ("No 3GPP info given...");
  2841. g_free (self->priv->current_operator_id);
  2842. self->priv->current_operator_id = NULL;
  2843. g_free (self->priv->current_operator_description);
  2844. self->priv->current_operator_description = NULL;
  2845. if (registration_state == QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING)
  2846. reg_state_3gpp = MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING;
  2847. else
  2848. reg_state_3gpp = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  2849. mm_iface_modem_3gpp_update_cs_registration_state (MM_IFACE_MODEM_3GPP (self), reg_state_3gpp);
  2850. mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), reg_state_3gpp);
  2851. mm_iface_modem_3gpp_update_access_technologies (MM_IFACE_MODEM_3GPP (self), MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
  2852. mm_iface_modem_3gpp_update_location (MM_IFACE_MODEM_3GPP (self), 0, 0);
  2853. return;
  2854. }
  2855. /* Get roaming status.
  2856. * TODO: QMI may report per-access-technology roaming indicators, for when
  2857. * the modem is connected to more than one network. How to handle those? */
  2858. roaming = QMI_NAS_ROAMING_INDICATOR_STATUS_OFF;
  2859. if (response_output)
  2860. qmi_message_nas_get_serving_system_output_get_roaming_indicator (response_output, &roaming, NULL);
  2861. else
  2862. qmi_indication_nas_serving_system_output_get_roaming_indicator (indication_output, &roaming, NULL);
  2863. /* Build MM registration states */
  2864. mm_cs_registration_state =
  2865. mm_modem_3gpp_registration_state_from_qmi_registration_state (
  2866. cs_attach_state,
  2867. registration_state,
  2868. (roaming == QMI_NAS_ROAMING_INDICATOR_STATUS_ON));
  2869. mm_ps_registration_state =
  2870. mm_modem_3gpp_registration_state_from_qmi_registration_state (
  2871. ps_attach_state,
  2872. registration_state,
  2873. (roaming == QMI_NAS_ROAMING_INDICATOR_STATUS_ON));
  2874. /* Get and cache operator ID/name */
  2875. if ((response_output &&
  2876. qmi_message_nas_get_serving_system_output_get_current_plmn (
  2877. response_output,
  2878. &mcc,
  2879. &mnc,
  2880. &description,
  2881. NULL)) ||
  2882. (indication_output &&
  2883. qmi_indication_nas_serving_system_output_get_current_plmn (
  2884. indication_output,
  2885. &mcc,
  2886. &mnc,
  2887. &description,
  2888. NULL))) {
  2889. /* When we don't have information about leading PCS digit, guess best */
  2890. g_free (self->priv->current_operator_id);
  2891. if (mnc >= 100)
  2892. self->priv->current_operator_id =
  2893. g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.3" G_GUINT16_FORMAT,
  2894. mcc,
  2895. mnc);
  2896. else
  2897. self->priv->current_operator_id =
  2898. g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.2" G_GUINT16_FORMAT,
  2899. mcc,
  2900. mnc);
  2901. g_free (self->priv->current_operator_description);
  2902. self->priv->current_operator_description = g_strdup (description);
  2903. }
  2904. /* If MNC comes with PCS digit, we must make sure the additional
  2905. * leading '0' is added */
  2906. if (((response_output &&
  2907. qmi_message_nas_get_serving_system_output_get_mnc_pcs_digit_include_status (
  2908. response_output,
  2909. &mcc,
  2910. &mnc,
  2911. &has_pcs_digit,
  2912. NULL)) ||
  2913. (indication_output &&
  2914. qmi_indication_nas_serving_system_output_get_mnc_pcs_digit_include_status (
  2915. indication_output,
  2916. &mcc,
  2917. &mnc,
  2918. &has_pcs_digit,
  2919. NULL))) &&
  2920. has_pcs_digit) {
  2921. g_free (self->priv->current_operator_id);
  2922. self->priv->current_operator_id =
  2923. g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.3" G_GUINT16_FORMAT,
  2924. mcc,
  2925. mnc);
  2926. }
  2927. /* Get 3GPP location LAC and CI */
  2928. lac = 0;
  2929. cid = 0;
  2930. if (response_output) {
  2931. qmi_message_nas_get_serving_system_output_get_lac_3gpp (response_output, &lac, NULL);
  2932. qmi_message_nas_get_serving_system_output_get_cid_3gpp (response_output, &cid, NULL);
  2933. } else {
  2934. qmi_indication_nas_serving_system_output_get_lac_3gpp (indication_output, &lac, NULL);
  2935. qmi_indication_nas_serving_system_output_get_cid_3gpp (indication_output, &cid, NULL);
  2936. }
  2937. /* Report new registration states */
  2938. mm_iface_modem_3gpp_update_cs_registration_state (MM_IFACE_MODEM_3GPP (self), mm_cs_registration_state);
  2939. mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), mm_ps_registration_state);
  2940. mm_iface_modem_3gpp_update_location (MM_IFACE_MODEM_3GPP (self), lac, cid);
  2941. /* Note: don't update access technologies with the ones retrieved here; they
  2942. * are not really the 'current' access technologies */
  2943. }
  2944. static void
  2945. get_serving_system_3gpp_ready (QmiClientNas *client,
  2946. GAsyncResult *res,
  2947. Run3gppRegistrationChecksContext *ctx)
  2948. {
  2949. QmiMessageNasGetServingSystemOutput *output;
  2950. GError *error = NULL;
  2951. output = qmi_client_nas_get_serving_system_finish (client, res, &error);
  2952. if (!output) {
  2953. g_prefix_error (&error, "QMI operation failed: ");
  2954. g_simple_async_result_take_error (ctx->result, error);
  2955. run_3gpp_registration_checks_context_complete_and_free (ctx);
  2956. return;
  2957. }
  2958. if (!qmi_message_nas_get_serving_system_output_get_result (output, &error)) {
  2959. g_prefix_error (&error, "Couldn't get serving system: ");
  2960. g_simple_async_result_take_error (ctx->result, error);
  2961. qmi_message_nas_get_serving_system_output_unref (output);
  2962. run_3gpp_registration_checks_context_complete_and_free (ctx);
  2963. return;
  2964. }
  2965. common_process_serving_system_3gpp (ctx->self, output, NULL);
  2966. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  2967. qmi_message_nas_get_serving_system_output_unref (output);
  2968. run_3gpp_registration_checks_context_complete_and_free (ctx);
  2969. }
  2970. #if defined WITH_NEWEST_QMI_COMMANDS
  2971. static gboolean
  2972. process_common_info (QmiNasServiceStatus service_status,
  2973. gboolean domain_valid,
  2974. QmiNasNetworkServiceDomain domain,
  2975. gboolean roaming_status_valid,
  2976. QmiNasRoamingStatus roaming_status,
  2977. gboolean forbidden_valid,
  2978. gboolean forbidden,
  2979. gboolean lac_valid,
  2980. guint16 lac,
  2981. gboolean cid_valid,
  2982. guint32 cid,
  2983. gboolean network_id_valid,
  2984. const gchar *mcc,
  2985. const gchar *mnc,
  2986. MMModem3gppRegistrationState *mm_cs_registration_state,
  2987. MMModem3gppRegistrationState *mm_ps_registration_state,
  2988. guint16 *mm_lac,
  2989. guint32 *mm_cid,
  2990. gchar **mm_operator_id)
  2991. {
  2992. MMModem3gppRegistrationState tmp_registration_state;
  2993. gboolean apply_cs;
  2994. gboolean apply_ps;
  2995. if (service_status != QMI_NAS_SERVICE_STATUS_LIMITED &&
  2996. service_status != QMI_NAS_SERVICE_STATUS_AVAILABLE &&
  2997. service_status != QMI_NAS_SERVICE_STATUS_LIMITED_REGIONAL)
  2998. return FALSE;
  2999. /* If we don't have domain, unknown */
  3000. if (!domain_valid)
  3001. tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3002. else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_NONE)
  3003. tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING;
  3004. else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN)
  3005. tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3006. else {
  3007. /* If we have CS or PS service domain, assume registered for now */
  3008. if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_CS)
  3009. apply_ps = FALSE;
  3010. else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_PS)
  3011. apply_cs = FALSE;
  3012. /* Check if we really are roaming or forbidden */
  3013. if (forbidden_valid && forbidden)
  3014. tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_DENIED;
  3015. else {
  3016. if (roaming_status_valid && roaming_status == QMI_NAS_ROAMING_STATUS_ON)
  3017. tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING;
  3018. else
  3019. tmp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
  3020. /* If we're registered either at home or roaming, try to get LAC/CID */
  3021. if (lac_valid)
  3022. *mm_lac = lac;
  3023. if (cid_valid)
  3024. *mm_cid = cid;
  3025. }
  3026. }
  3027. if (apply_cs)
  3028. *mm_cs_registration_state = tmp_registration_state;
  3029. if (apply_ps)
  3030. *mm_cs_registration_state = tmp_registration_state;
  3031. if (network_id_valid) {
  3032. *mm_operator_id = g_malloc (7);
  3033. memcpy (*mm_operator_id, mcc, 3);
  3034. if (mnc[2] == 0xFF) {
  3035. memcpy (*mm_operator_id, mnc, 2);
  3036. (*mm_operator_id)[5] = '\0';
  3037. } else {
  3038. memcpy (*mm_operator_id, mnc, 3);
  3039. (*mm_operator_id)[6] = '\0';
  3040. }
  3041. }
  3042. return TRUE;
  3043. }
  3044. static gboolean
  3045. process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output,
  3046. QmiIndicationNasSystemInfoOutput *indication_output,
  3047. MMModem3gppRegistrationState *mm_cs_registration_state,
  3048. MMModem3gppRegistrationState *mm_ps_registration_state,
  3049. guint16 *mm_lac,
  3050. guint32 *mm_cid,
  3051. gchar **mm_operator_id)
  3052. {
  3053. QmiNasServiceStatus service_status;
  3054. gboolean domain_valid;
  3055. QmiNasNetworkServiceDomain domain;
  3056. gboolean roaming_status_valid;
  3057. QmiNasRoamingStatus roaming_status;
  3058. gboolean forbidden_valid;
  3059. gboolean forbidden;
  3060. gboolean lac_valid;
  3061. guint16 lac;
  3062. gboolean cid_valid;
  3063. guint32 cid;
  3064. gboolean network_id_valid;
  3065. const gchar *mcc;
  3066. const gchar *mnc;
  3067. g_assert ((response_output != NULL && indication_output == NULL) ||
  3068. (response_output == NULL && indication_output != NULL));
  3069. *mm_ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3070. *mm_cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3071. *mm_lac = 0;
  3072. *mm_cid = 0;
  3073. g_free (*mm_operator_id);
  3074. *mm_operator_id = NULL;
  3075. if (response_output) {
  3076. if (!qmi_message_nas_get_system_info_output_get_gsm_service_status (
  3077. response_output,
  3078. &service_status,
  3079. NULL, /* true_service_status */
  3080. NULL, /* preferred_data_path */
  3081. NULL) ||
  3082. !qmi_message_nas_get_system_info_output_get_gsm_system_info (
  3083. response_output,
  3084. &domain_valid, &domain,
  3085. NULL, NULL, /* service_capability */
  3086. &roaming_status_valid, &roaming_status,
  3087. &forbidden_valid, &forbidden,
  3088. &lac_valid, &lac,
  3089. &cid_valid, &cid,
  3090. NULL, NULL, NULL, /* registration_reject_info */
  3091. &network_id_valid, &mcc, &mnc,
  3092. &egprs_support_valid, &egprs_support,
  3093. NULL, NULL, /* dtm_support */
  3094. NULL)) {
  3095. mm_dbg ("No GSM service reported");
  3096. /* No GSM service */
  3097. return FALSE;
  3098. }
  3099. } else {
  3100. if (!qmi_indication_nas_system_info_output_get_gsm_service_status (
  3101. indication_output,
  3102. &service_status,
  3103. NULL, /* true_service_status */
  3104. NULL, /* preferred_data_path */
  3105. NULL) ||
  3106. !qmi_indication_nas_system_info_output_get_gsm_system_info (
  3107. indication_output,
  3108. &domain_valid, &domain,
  3109. NULL, NULL, /* service_capability */
  3110. &roaming_status_valid, &roaming_status,
  3111. &forbidden_valid, &forbidden,
  3112. &lac_valid, &lac,
  3113. &cid_valid, &cid,
  3114. NULL, NULL, NULL, /* registration_reject_info */
  3115. &network_id_valid, &mcc, &mnc,
  3116. &egprs_support_valid, &egprs_support,
  3117. NULL, NULL, /* dtm_support */
  3118. NULL)) {
  3119. mm_dbg ("No GSM service reported");
  3120. /* No GSM service */
  3121. return FALSE;
  3122. }
  3123. }
  3124. if (!process_common_info (service_status,
  3125. domain_valid, domain,
  3126. roaming_status_valid, roaming_status,
  3127. forbidden_valid, forbidden,
  3128. lac_valid, lac,
  3129. cid_valid, cid,
  3130. network_id_valid, mcc, mnc,
  3131. mm_cs_registration_state,
  3132. mm_ps_registration_state,
  3133. mm_lac,
  3134. mm_cid,
  3135. mm_operator_id)) {
  3136. mm_dbg ("No GSM service registered");
  3137. return FALSE;
  3138. }
  3139. return TRUE;
  3140. }
  3141. static gboolean
  3142. process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output,
  3143. QmiIndicationNasSystemInfoOutput *indication_output,
  3144. MMModem3gppRegistrationState *mm_cs_registration_state,
  3145. MMModem3gppRegistrationState *mm_ps_registration_state,
  3146. guint16 *mm_lac,
  3147. guint32 *mm_cid,
  3148. gchar **mm_operator_id)
  3149. {
  3150. QmiNasServiceStatus service_status;
  3151. gboolean domain_valid;
  3152. QmiNasNetworkServiceDomain domain;
  3153. gboolean roaming_status_valid;
  3154. QmiNasRoamingStatus roaming_status;
  3155. gboolean forbidden_valid;
  3156. gboolean forbidden;
  3157. gboolean lac_valid;
  3158. guint16 lac;
  3159. gboolean cid_valid;
  3160. guint32 cid;
  3161. gboolean network_id_valid;
  3162. const gchar *mcc;
  3163. const gchar *mnc;
  3164. gboolean hs_service_valid;
  3165. QmiNasWcdmaHsService hs_service;
  3166. g_assert ((response_output != NULL && indication_output == NULL) ||
  3167. (response_output == NULL && indication_output != NULL));
  3168. *mm_ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3169. *mm_cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3170. *mm_lac = 0;
  3171. *mm_cid = 0;
  3172. g_free (*mm_operator_id);
  3173. *mm_operator_id = NULL;
  3174. if (response_output) {
  3175. if (!qmi_message_nas_get_system_info_output_get_wcdma_service_status (
  3176. response_output,
  3177. &service_status,
  3178. NULL, /* true_service_status */
  3179. NULL, /* preferred_data_path */
  3180. NULL) ||
  3181. !qmi_message_nas_get_system_info_output_get_wcdma_system_info (
  3182. response_output,
  3183. &domain_valid, &domain,
  3184. NULL, NULL, /* service_capability */
  3185. &roaming_status_valid, &roaming_status,
  3186. &forbidden_valid, &forbidden,
  3187. &lac_valid, &lac,
  3188. &cid_valid, &cid,
  3189. NULL, NULL, NULL, /* registration_reject_info */
  3190. &network_id_valid, &mcc, &mnc,
  3191. NULL, NULL, /* hs_call_status */
  3192. &hs_service_valid, &hs_service,
  3193. NULL, NULL, /* primary_scrambling_code */
  3194. NULL)) {
  3195. mm_dbg ("No WCDMA service reported");
  3196. /* No GSM service */
  3197. return FALSE;
  3198. }
  3199. } else {
  3200. if (!qmi_indication_nas_system_info_output_get_wcdma_service_status (
  3201. indication_output,
  3202. &service_status,
  3203. NULL, /* true_service_status */
  3204. NULL, /* preferred_data_path */
  3205. NULL) ||
  3206. !qmi_indication_nas_system_info_output_get_wcdma_system_info (
  3207. indication_output,
  3208. &domain_valid, &domain,
  3209. NULL, NULL, /* service_capability */
  3210. &roaming_status_valid, &roaming_status,
  3211. &forbidden_valid, &forbidden,
  3212. &lac_valid, &lac,
  3213. &cid_valid, &cid,
  3214. NULL, NULL, NULL, /* registration_reject_info */
  3215. &network_id_valid, &mcc, &mnc,
  3216. NULL, NULL, /* hs_call_status */
  3217. &hs_service_valid, &hs_service,
  3218. NULL, NULL, /* primary_scrambling_code */
  3219. NULL)) {
  3220. mm_dbg ("No WCDMA service reported");
  3221. /* No GSM service */
  3222. return FALSE;
  3223. }
  3224. }
  3225. if (!process_common_info (service_status,
  3226. domain_valid, domain,
  3227. roaming_status_valid, roaming_status,
  3228. forbidden_valid, forbidden,
  3229. lac_valid, lac,
  3230. cid_valid, cid,
  3231. network_id_valid, mcc, mnc,
  3232. mm_cs_registration_state,
  3233. mm_ps_registration_state,
  3234. mm_lac,
  3235. mm_cid,
  3236. mm_operator_id)) {
  3237. mm_dbg ("No WCDMA service registered");
  3238. return FALSE;
  3239. }
  3240. return TRUE;
  3241. }
  3242. static gboolean
  3243. process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output,
  3244. QmiIndicationNasSystemInfoOutput *indication_output,
  3245. MMModem3gppRegistrationState *mm_cs_registration_state,
  3246. MMModem3gppRegistrationState *mm_ps_registration_state,
  3247. guint16 *mm_lac,
  3248. guint32 *mm_cid,
  3249. gchar **mm_operator_id)
  3250. {
  3251. QmiNasServiceStatus service_status;
  3252. gboolean domain_valid;
  3253. QmiNasNetworkServiceDomain domain;
  3254. gboolean roaming_status_valid;
  3255. QmiNasRoamingStatus roaming_status;
  3256. gboolean forbidden_valid;
  3257. gboolean forbidden;
  3258. gboolean lac_valid;
  3259. guint16 lac;
  3260. gboolean cid_valid;
  3261. guint32 cid;
  3262. gboolean network_id_valid;
  3263. const gchar *mcc;
  3264. const gchar *mnc;
  3265. g_assert ((response_output != NULL && indication_output == NULL) ||
  3266. (response_output == NULL && indication_output != NULL));
  3267. *mm_ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3268. *mm_cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3269. *mm_lac = 0;
  3270. *mm_cid = 0;
  3271. g_free (*mm_operator_id);
  3272. *mm_operator_id = NULL;
  3273. if (response_output) {
  3274. if (!qmi_message_nas_get_system_info_output_get_lte_service_status (
  3275. response_output,
  3276. &service_status,
  3277. NULL, /* true_service_status */
  3278. NULL, /* preferred_data_path */
  3279. NULL) ||
  3280. !qmi_message_nas_get_system_info_output_get_lte_system_info (
  3281. response_output,
  3282. &domain_valid, &domain,
  3283. NULL, NULL, /* service_capability */
  3284. &roaming_status_valid, &roaming_status,
  3285. &forbidden_valid, &forbidden,
  3286. &lac_valid, &lac,
  3287. &cid_valid, &cid,
  3288. NULL, NULL, NULL, /* registration_reject_info */
  3289. &network_id_valid, &mcc, &mnc,
  3290. NULL, NULL, /* tac */
  3291. NULL)) {
  3292. mm_dbg ("No LTE service reported");
  3293. /* No GSM service */
  3294. return FALSE;
  3295. }
  3296. } else {
  3297. if (!qmi_indication_nas_system_info_output_get_lte_service_status (
  3298. indication_output,
  3299. &service_status,
  3300. NULL, /* true_service_status */
  3301. NULL, /* preferred_data_path */
  3302. NULL) ||
  3303. !qmi_indication_nas_system_info_output_get_lte_system_info (
  3304. indication_output,
  3305. &domain_valid, &domain,
  3306. NULL, NULL, /* service_capability */
  3307. &roaming_status_valid, &roaming_status,
  3308. &forbidden_valid, &forbidden,
  3309. &lac_valid, &lac,
  3310. &cid_valid, &cid,
  3311. NULL, NULL, NULL, /* registration_reject_info */
  3312. &network_id_valid, &mcc, &mnc,
  3313. NULL, NULL, /* tac */
  3314. NULL)) {
  3315. mm_dbg ("No LTE service reported");
  3316. /* No GSM service */
  3317. return FALSE;
  3318. }
  3319. }
  3320. if (!process_common_info (service_status,
  3321. domain_valid, domain,
  3322. roaming_status_valid, roaming_status,
  3323. forbidden_valid, forbidden,
  3324. lac_valid, lac,
  3325. cid_valid, cid,
  3326. network_id_valid, mcc, mnc,
  3327. mm_cs_registration_state,
  3328. mm_ps_registration_state,
  3329. mm_lac,
  3330. mm_cid,
  3331. mm_operator_id)) {
  3332. mm_dbg ("No LTE service registered");
  3333. return FALSE;
  3334. }
  3335. return TRUE;
  3336. }
  3337. static void
  3338. common_process_system_info_3gpp (MMBroadbandModemQmi *self,
  3339. QmiMessageNasGetSystemInfoOutput *response_output,
  3340. QmiIndicationNasSystemInfoOutput *indication_output)
  3341. {
  3342. MMModem3gppRegistrationState cs_registration_state;
  3343. MMModem3gppRegistrationState ps_registration_state;
  3344. guint16 lac;
  3345. guint32 cid;
  3346. gchar *operator_id;
  3347. ps_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3348. cs_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
  3349. lac = 0;
  3350. cid = 0;
  3351. operator_id = NULL;
  3352. /* Process infos, with the following priority:
  3353. * LTE > WCDMA > GSM
  3354. * The first one giving results will be the one reported.
  3355. */
  3356. if (!process_lte_info (response_output, indication_output,
  3357. &cs_registration_state,
  3358. &ps_registration_state,
  3359. &lac,
  3360. &cid,
  3361. &operator_id) &&
  3362. !process_wcdma_info (response_output, indication_output,
  3363. &cs_registration_state,
  3364. &ps_registration_state,
  3365. &lac,
  3366. &cid,
  3367. &operator_id) &&
  3368. !process_gsm_info (response_output, indication_output,
  3369. &cs_registration_state,
  3370. &ps_registration_state,
  3371. &lac,
  3372. &cid,
  3373. &operator_id)) {
  3374. mm_dbg ("No service (GSM, WCDMA or LTE) reported");
  3375. }
  3376. /* Cache current operator ID */
  3377. if (operator_id) {
  3378. g_free (self->priv->current_operator_id);
  3379. self->priv->current_operator_id = operator_id;
  3380. }
  3381. /* Report new registration states */
  3382. mm_iface_modem_3gpp_update_cs_registration_state (MM_IFACE_MODEM_3GPP (self), cs_registration_state);
  3383. mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), ps_registration_state);
  3384. mm_iface_modem_3gpp_update_location (MM_IFACE_MODEM_3GPP (self), lac, cid);
  3385. }
  3386. static void
  3387. get_system_info_ready (QmiClientNas *client,
  3388. GAsyncResult *res,
  3389. Run3gppRegistrationChecksContext *ctx)
  3390. {
  3391. QmiMessageNasGetSystemInfoOutput *output;
  3392. GError *error = NULL;
  3393. output = qmi_client_nas_get_system_info_finish (client, res, &error);
  3394. if (!output) {
  3395. g_prefix_error (&error, "QMI operation failed: ");
  3396. g_simple_async_result_take_error (ctx->result, error);
  3397. run_3gpp_registration_checks_context_complete_and_free (ctx);
  3398. return;
  3399. }
  3400. if (!qmi_message_nas_get_system_info_output_get_result (output, &error)) {
  3401. g_prefix_error (&error, "Couldn't get system info: ");
  3402. g_simple_async_result_take_error (ctx->result, error);
  3403. qmi_message_nas_get_system_info_output_unref (output);
  3404. run_3gpp_registration_checks_context_complete_and_free (ctx);
  3405. return;
  3406. }
  3407. common_process_system_info_3gpp (ctx->self, output, NULL);
  3408. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  3409. qmi_message_nas_get_system_info_output_unref (output);
  3410. run_3gpp_registration_checks_context_complete_and_free (ctx);
  3411. }
  3412. #endif /* WITH_NEWEST_QMI_COMMANDS */
  3413. static void
  3414. modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self,
  3415. gboolean cs_supported,
  3416. gboolean ps_supported,
  3417. gboolean eps_supported,
  3418. GAsyncReadyCallback callback,
  3419. gpointer user_data)
  3420. {
  3421. Run3gppRegistrationChecksContext *ctx;
  3422. QmiClient *client = NULL;
  3423. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  3424. QMI_SERVICE_NAS, &client,
  3425. callback, user_data))
  3426. return;
  3427. ctx = g_new0 (Run3gppRegistrationChecksContext, 1);
  3428. ctx->self = g_object_ref (self);
  3429. ctx->client = g_object_ref (client);
  3430. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  3431. callback,
  3432. user_data,
  3433. modem_3gpp_run_registration_checks);
  3434. #if defined WITH_NEWEST_QMI_COMMANDS
  3435. /* System Info was added in NAS 1.8 */
  3436. if (qmi_client_check_version (client, 1, 8)) {
  3437. qmi_client_nas_get_system_info (ctx->client,
  3438. NULL,
  3439. 10,
  3440. NULL,
  3441. (GAsyncReadyCallback)get_system_info_ready,
  3442. ctx);
  3443. return;
  3444. }
  3445. #endif /* WITH_NEWEST_QMI_COMMANDS */
  3446. qmi_client_nas_get_serving_system (ctx->client,
  3447. NULL,
  3448. 10,
  3449. NULL,
  3450. (GAsyncReadyCallback)get_serving_system_3gpp_ready,
  3451. ctx);
  3452. }
  3453. /*****************************************************************************/
  3454. /* Enable/Disable unsolicited registration events (3GPP interface) */
  3455. typedef struct {
  3456. MMBroadbandModemQmi *self;
  3457. QmiClientNas *client;
  3458. GSimpleAsyncResult *result;
  3459. gboolean enable; /* TRUE for enabling, FALSE for disabling */
  3460. } UnsolicitedRegistrationEventsContext;
  3461. static void
  3462. unsolicited_registration_events_context_complete_and_free (UnsolicitedRegistrationEventsContext *ctx)
  3463. {
  3464. g_simple_async_result_complete_in_idle (ctx->result);
  3465. g_object_unref (ctx->result);
  3466. g_object_unref (ctx->client);
  3467. g_object_unref (ctx->self);
  3468. g_free (ctx);
  3469. }
  3470. static UnsolicitedRegistrationEventsContext *
  3471. unsolicited_registration_events_context_new (MMBroadbandModemQmi *self,
  3472. QmiClient *client,
  3473. gboolean enable,
  3474. GAsyncReadyCallback callback,
  3475. gpointer user_data)
  3476. {
  3477. UnsolicitedRegistrationEventsContext *ctx;
  3478. ctx = g_new0 (UnsolicitedRegistrationEventsContext, 1);
  3479. ctx->self = g_object_ref (self);
  3480. ctx->client = g_object_ref (client);
  3481. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  3482. callback,
  3483. user_data,
  3484. unsolicited_registration_events_context_new);
  3485. ctx->enable = FALSE;
  3486. return ctx;
  3487. }
  3488. static gboolean
  3489. modem_3gpp_enable_disable_unsolicited_registration_events_finish (MMIfaceModem3gpp *self,
  3490. GAsyncResult *res,
  3491. GError **error)
  3492. {
  3493. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  3494. }
  3495. static void
  3496. ri_serving_system_or_system_info_ready (QmiClientNas *client,
  3497. GAsyncResult *res,
  3498. UnsolicitedRegistrationEventsContext *ctx)
  3499. {
  3500. QmiMessageNasRegisterIndicationsOutput *output = NULL;
  3501. GError *error = NULL;
  3502. output = qmi_client_nas_register_indications_finish (client, res, &error);
  3503. if (!output) {
  3504. mm_dbg ("QMI operation failed: '%s'", error->message);
  3505. g_error_free (error);
  3506. } else if (!qmi_message_nas_register_indications_output_get_result (output, &error)) {
  3507. mm_dbg ("Couldn't register indications: '%s'", error->message);
  3508. g_error_free (error);
  3509. }
  3510. if (output)
  3511. qmi_message_nas_register_indications_output_unref (output);
  3512. /* Just ignore errors for now */
  3513. ctx->self->priv->unsolicited_registration_events_enabled = ctx->enable;
  3514. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  3515. unsolicited_registration_events_context_complete_and_free (ctx);
  3516. }
  3517. static void
  3518. common_enable_disable_unsolicited_registration_events_serving_system (UnsolicitedRegistrationEventsContext *ctx)
  3519. {
  3520. QmiMessageNasRegisterIndicationsInput *input;
  3521. input = qmi_message_nas_register_indications_input_new ();
  3522. qmi_message_nas_register_indications_input_set_serving_system_events (input, ctx->enable, NULL);
  3523. qmi_client_nas_register_indications (
  3524. ctx->client,
  3525. input,
  3526. 5,
  3527. NULL,
  3528. (GAsyncReadyCallback)ri_serving_system_or_system_info_ready,
  3529. ctx);
  3530. qmi_message_nas_register_indications_input_unref (input);
  3531. }
  3532. #if defined WITH_NEWEST_QMI_COMMANDS
  3533. static void
  3534. common_enable_disable_unsolicited_registration_events_system_info (UnsolicitedRegistrationEventsContext *ctx)
  3535. {
  3536. QmiMessageNasRegisterIndicationsInput *input;
  3537. input = qmi_message_nas_register_indications_input_new ();
  3538. qmi_message_nas_register_indications_input_set_system_info (input, ctx->enable, NULL);
  3539. qmi_client_nas_register_indications (
  3540. ctx->client,
  3541. input,
  3542. 5,
  3543. NULL,
  3544. (GAsyncReadyCallback)ri_serving_system_or_system_info_ready,
  3545. ctx);
  3546. qmi_message_nas_register_indications_input_unref (input);
  3547. }
  3548. #endif /* WITH_NEWEST_QMI_COMMANDS */
  3549. static void
  3550. modem_3gpp_disable_unsolicited_registration_events (MMIfaceModem3gpp *self,
  3551. gboolean cs_supported,
  3552. gboolean ps_supported,
  3553. gboolean eps_supported,
  3554. GAsyncReadyCallback callback,
  3555. gpointer user_data)
  3556. {
  3557. UnsolicitedRegistrationEventsContext *ctx;
  3558. QmiClient *client = NULL;
  3559. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  3560. QMI_SERVICE_NAS, &client,
  3561. callback, user_data))
  3562. return;
  3563. ctx = unsolicited_registration_events_context_new (MM_BROADBAND_MODEM_QMI (self),
  3564. client,
  3565. FALSE,
  3566. callback,
  3567. user_data);
  3568. #if defined WITH_NEWEST_QMI_COMMANDS
  3569. /* System Info was added in NAS 1.8 */
  3570. if (qmi_client_check_version (client, 1, 8)) {
  3571. common_enable_disable_unsolicited_registration_events_system_info (ctx);
  3572. return;
  3573. }
  3574. #endif /* WITH_NEWEST_QMI_COMMANDS */
  3575. /* Ability to explicitly enable/disable serving system indications was
  3576. * added in NAS 1.2 */
  3577. if (qmi_client_check_version (client, 1, 2)) {
  3578. common_enable_disable_unsolicited_registration_events_serving_system (ctx);
  3579. return;
  3580. }
  3581. /* Devices with NAS < 1.2 will just always issue serving system indications */
  3582. g_simple_async_result_set_error (ctx->result,
  3583. MM_CORE_ERROR,
  3584. MM_CORE_ERROR_FAILED,
  3585. "Device doesn't allow disabling registration events");
  3586. ctx->self->priv->unsolicited_registration_events_enabled = FALSE;
  3587. unsolicited_registration_events_context_complete_and_free (ctx);
  3588. }
  3589. static void
  3590. modem_3gpp_enable_unsolicited_registration_events (MMIfaceModem3gpp *self,
  3591. gboolean cs_supported,
  3592. gboolean ps_supported,
  3593. gboolean eps_supported,
  3594. GAsyncReadyCallback callback,
  3595. gpointer user_data)
  3596. {
  3597. UnsolicitedRegistrationEventsContext *ctx;
  3598. QmiClient *client = NULL;
  3599. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  3600. QMI_SERVICE_NAS, &client,
  3601. callback, user_data))
  3602. return;
  3603. ctx = unsolicited_registration_events_context_new (MM_BROADBAND_MODEM_QMI (self),
  3604. client,
  3605. TRUE,
  3606. callback,
  3607. user_data);
  3608. /* Ability to explicitly enable/disable serving system indications was
  3609. * added in NAS 1.2 */
  3610. if (qmi_client_check_version (client, 1, 2)) {
  3611. common_enable_disable_unsolicited_registration_events_serving_system (ctx);
  3612. return;
  3613. }
  3614. /* Devices with NAS < 1.2 will just always issue serving system indications */
  3615. mm_dbg ("Assuming serving system indications are always enabled");
  3616. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  3617. ctx->self->priv->unsolicited_registration_events_enabled = TRUE;
  3618. unsolicited_registration_events_context_complete_and_free (ctx);
  3619. }
  3620. /*****************************************************************************/
  3621. /* Registration checks (CDMA interface) */
  3622. typedef struct {
  3623. MMBroadbandModemQmi *self;
  3624. QmiClientNas *client;
  3625. GSimpleAsyncResult *result;
  3626. } RunCdmaRegistrationChecksContext;
  3627. static void
  3628. run_cdma_registration_checks_context_complete_and_free (RunCdmaRegistrationChecksContext *ctx)
  3629. {
  3630. g_simple_async_result_complete (ctx->result);
  3631. g_object_unref (ctx->result);
  3632. g_object_unref (ctx->client);
  3633. g_object_unref (ctx->self);
  3634. g_slice_free (RunCdmaRegistrationChecksContext, ctx);
  3635. }
  3636. static gboolean
  3637. modem_cdma_run_registration_checks_finish (MMIfaceModemCdma *self,
  3638. GAsyncResult *res,
  3639. GError **error)
  3640. {
  3641. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  3642. }
  3643. static void
  3644. common_process_serving_system_cdma (MMBroadbandModemQmi *self,
  3645. QmiMessageNasGetServingSystemOutput *response_output,
  3646. QmiIndicationNasServingSystemOutput *indication_output)
  3647. {
  3648. QmiNasRegistrationState registration_state;
  3649. QmiNasNetworkType selected_network;
  3650. GArray *radio_interfaces;
  3651. GArray *data_service_capabilities;
  3652. MMModemAccessTechnology mm_access_technologies;
  3653. MMModemCdmaRegistrationState mm_cdma1x_registration_state;
  3654. MMModemCdmaRegistrationState mm_evdo_registration_state;
  3655. guint16 sid = 0;
  3656. guint16 nid = 0;
  3657. guint16 bs_id = 0;
  3658. gint32 bs_longitude = MM_LOCATION_LONGITUDE_UNKNOWN;
  3659. gint32 bs_latitude = MM_LOCATION_LATITUDE_UNKNOWN;
  3660. if (response_output)
  3661. qmi_message_nas_get_serving_system_output_get_serving_system (
  3662. response_output,
  3663. &registration_state,
  3664. NULL, /* cs_attach_state */
  3665. NULL, /* ps_attach_state */
  3666. &selected_network,
  3667. &radio_interfaces,
  3668. NULL);
  3669. else
  3670. qmi_indication_nas_serving_system_output_get_serving_system (
  3671. indication_output,
  3672. &registration_state,
  3673. NULL, /* cs_attach_state */
  3674. NULL, /* ps_attach_state */
  3675. &selected_network,
  3676. &radio_interfaces,
  3677. NULL);
  3678. /* Build access technologies mask */
  3679. data_service_capabilities = NULL;
  3680. if (response_output)
  3681. qmi_message_nas_get_serving_system_output_get_data_service_capability (response_output,
  3682. &data_service_capabilities,
  3683. NULL);
  3684. else
  3685. qmi_indication_nas_serving_system_output_get_data_service_capability (indication_output,
  3686. &data_service_capabilities,
  3687. NULL);
  3688. if (data_service_capabilities)
  3689. mm_access_technologies =
  3690. mm_modem_access_technologies_from_qmi_data_capability_array (data_service_capabilities);
  3691. else
  3692. mm_access_technologies =
  3693. mm_modem_access_technologies_from_qmi_radio_interface_array (radio_interfaces);
  3694. /* Only process 3GPP2 info */
  3695. if (selected_network == QMI_NAS_NETWORK_TYPE_3GPP2 ||
  3696. (selected_network == QMI_NAS_NETWORK_TYPE_UNKNOWN &&
  3697. (mm_access_technologies & MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK))) {
  3698. mm_dbg ("Processing CDMA info...");
  3699. } else {
  3700. mm_dbg ("No CDMA info given...");
  3701. mm_iface_modem_cdma_update_cdma1x_registration_state (MM_IFACE_MODEM_CDMA (self),
  3702. MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
  3703. 0, 0);
  3704. mm_iface_modem_cdma_update_evdo_registration_state (MM_IFACE_MODEM_CDMA (self),
  3705. MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
  3706. mm_iface_modem_cdma_update_access_technologies (MM_IFACE_MODEM_CDMA (self),
  3707. MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
  3708. mm_iface_modem_location_cdma_bs_clear (MM_IFACE_MODEM_LOCATION (self));
  3709. return;
  3710. }
  3711. /* Get SID/NID */
  3712. if (response_output)
  3713. qmi_message_nas_get_serving_system_output_get_cdma_system_id (response_output, &sid, &nid, NULL);
  3714. else
  3715. qmi_indication_nas_serving_system_output_get_cdma_system_id (indication_output, &sid, &nid, NULL);
  3716. /* Get BS location */
  3717. if (response_output)
  3718. qmi_message_nas_get_serving_system_output_get_cdma_base_station_info (response_output, &bs_id, &bs_latitude, &bs_longitude, NULL);
  3719. else
  3720. qmi_indication_nas_serving_system_output_get_cdma_base_station_info (indication_output, &bs_id, &bs_latitude, &bs_longitude, NULL);
  3721. /* Build generic registration states */
  3722. if (mm_access_technologies & MM_IFACE_MODEM_CDMA_ALL_CDMA1X_ACCESS_TECHNOLOGIES_MASK)
  3723. mm_cdma1x_registration_state = mm_modem_cdma_registration_state_from_qmi_registration_state (registration_state);
  3724. else
  3725. mm_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
  3726. if (mm_access_technologies & MM_IFACE_MODEM_CDMA_ALL_EVDO_ACCESS_TECHNOLOGIES_MASK)
  3727. mm_evdo_registration_state = mm_modem_cdma_registration_state_from_qmi_registration_state (registration_state);
  3728. else
  3729. mm_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
  3730. /* Process per-technology roaming flags */
  3731. if (response_output) {
  3732. GArray *array;
  3733. if (qmi_message_nas_get_serving_system_output_get_roaming_indicator_list (response_output, &array, NULL)) {
  3734. guint i;
  3735. for (i = 0; i < array->len; i++) {
  3736. QmiMessageNasGetServingSystemOutputRoamingIndicatorListElement *element;
  3737. element = &g_array_index (array, QmiMessageNasGetServingSystemOutputRoamingIndicatorListElement, i);
  3738. if (element->radio_interface == QMI_NAS_RADIO_INTERFACE_CDMA_1X &&
  3739. mm_cdma1x_registration_state == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED) {
  3740. if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_ON)
  3741. mm_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
  3742. else if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_OFF)
  3743. mm_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
  3744. } else if (element->radio_interface == QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO &&
  3745. mm_evdo_registration_state == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED) {
  3746. if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_ON)
  3747. mm_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
  3748. else if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_OFF)
  3749. mm_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
  3750. }
  3751. }
  3752. }
  3753. } else {
  3754. GArray *array;
  3755. if (qmi_indication_nas_serving_system_output_get_roaming_indicator_list (indication_output, &array, NULL)) {
  3756. guint i;
  3757. for (i = 0; i < array->len; i++) {
  3758. QmiIndicationNasServingSystemOutputRoamingIndicatorListElement *element;
  3759. element = &g_array_index (array, QmiIndicationNasServingSystemOutputRoamingIndicatorListElement, i);
  3760. if (element->radio_interface == QMI_NAS_RADIO_INTERFACE_CDMA_1X &&
  3761. mm_cdma1x_registration_state == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED) {
  3762. if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_ON)
  3763. mm_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
  3764. else if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_OFF)
  3765. mm_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
  3766. } else if (element->radio_interface == QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO &&
  3767. mm_evdo_registration_state == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED) {
  3768. if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_ON)
  3769. mm_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
  3770. else if (element->roaming_indicator == QMI_NAS_ROAMING_INDICATOR_STATUS_OFF)
  3771. mm_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
  3772. }
  3773. }
  3774. }
  3775. }
  3776. /* Note: don't rely on the 'Detailed Service Status', it's not always given. */
  3777. /* Report new registration states */
  3778. mm_iface_modem_cdma_update_cdma1x_registration_state (MM_IFACE_MODEM_CDMA (self),
  3779. mm_cdma1x_registration_state,
  3780. sid,
  3781. nid);
  3782. mm_iface_modem_cdma_update_evdo_registration_state (MM_IFACE_MODEM_CDMA (self),
  3783. mm_evdo_registration_state);
  3784. /* Note: don't update access technologies with the ones retrieved here; they
  3785. * are not really the 'current' access technologies */
  3786. /* Longitude and latitude given in units of 0.25 secs
  3787. * Note that multiplying by 0.25 is like dividing by 4, so 60*60*4=14400 */
  3788. #define QMI_LONGITUDE_TO_DEGREES(longitude) \
  3789. (longitude != MM_LOCATION_LONGITUDE_UNKNOWN ? \
  3790. (((gdouble)longitude) / 14400.0) : \
  3791. MM_LOCATION_LONGITUDE_UNKNOWN)
  3792. #define QMI_LATITUDE_TO_DEGREES(latitude) \
  3793. (latitude != MM_LOCATION_LATITUDE_UNKNOWN ? \
  3794. (((gdouble)latitude) / 14400.0) : \
  3795. MM_LOCATION_LATITUDE_UNKNOWN)
  3796. mm_iface_modem_location_cdma_bs_update (MM_IFACE_MODEM_LOCATION (self),
  3797. QMI_LONGITUDE_TO_DEGREES (bs_longitude),
  3798. QMI_LATITUDE_TO_DEGREES (bs_latitude));
  3799. }
  3800. static void
  3801. get_serving_system_cdma_ready (QmiClientNas *client,
  3802. GAsyncResult *res,
  3803. RunCdmaRegistrationChecksContext *ctx)
  3804. {
  3805. QmiMessageNasGetServingSystemOutput *output;
  3806. GError *error = NULL;
  3807. output = qmi_client_nas_get_serving_system_finish (client, res, &error);
  3808. if (!output) {
  3809. g_prefix_error (&error, "QMI operation failed: ");
  3810. g_simple_async_result_take_error (ctx->result, error);
  3811. run_cdma_registration_checks_context_complete_and_free (ctx);
  3812. return;
  3813. }
  3814. if (!qmi_message_nas_get_serving_system_output_get_result (output, &error)) {
  3815. g_prefix_error (&error, "Couldn't get serving system: ");
  3816. g_simple_async_result_take_error (ctx->result, error);
  3817. qmi_message_nas_get_serving_system_output_unref (output);
  3818. run_cdma_registration_checks_context_complete_and_free (ctx);
  3819. return;
  3820. }
  3821. common_process_serving_system_cdma (ctx->self, output, NULL);
  3822. qmi_message_nas_get_serving_system_output_unref (output);
  3823. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  3824. run_cdma_registration_checks_context_complete_and_free (ctx);
  3825. }
  3826. static void
  3827. modem_cdma_run_registration_checks (MMIfaceModemCdma *self,
  3828. gboolean cdma1x_supported,
  3829. gboolean evdo_supported,
  3830. GAsyncReadyCallback callback,
  3831. gpointer user_data)
  3832. {
  3833. RunCdmaRegistrationChecksContext *ctx;
  3834. QmiClient *client = NULL;
  3835. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  3836. QMI_SERVICE_NAS, &client,
  3837. callback, user_data))
  3838. return;
  3839. /* Setup context */
  3840. ctx = g_slice_new0 (RunCdmaRegistrationChecksContext);
  3841. ctx->self = g_object_ref (self);
  3842. ctx->client = g_object_ref (client);
  3843. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  3844. callback,
  3845. user_data,
  3846. modem_cdma_run_registration_checks);
  3847. /* TODO: Run Get System Info in NAS >= 1.8 */
  3848. qmi_client_nas_get_serving_system (ctx->client,
  3849. NULL,
  3850. 10,
  3851. NULL,
  3852. (GAsyncReadyCallback)get_serving_system_cdma_ready,
  3853. ctx);
  3854. }
  3855. /*****************************************************************************/
  3856. /* Setup/Cleanup unsolicited registration event handlers
  3857. * (3GPP and CDMA interface) */
  3858. static gboolean
  3859. common_setup_cleanup_unsolicited_registration_events_finish (MMBroadbandModemQmi *self,
  3860. GAsyncResult *res,
  3861. GError **error)
  3862. {
  3863. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  3864. }
  3865. #if defined WITH_NEWEST_QMI_COMMANDS
  3866. static void
  3867. system_info_indication_cb (QmiClientNas *client,
  3868. QmiIndicationNasSystemInfoOutput *output,
  3869. MMBroadbandModemQmi *self)
  3870. {
  3871. if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self)))
  3872. common_process_system_info_3gpp (self, NULL, output);
  3873. }
  3874. #endif
  3875. static void
  3876. serving_system_indication_cb (QmiClientNas *client,
  3877. QmiIndicationNasServingSystemOutput *output,
  3878. MMBroadbandModemQmi *self)
  3879. {
  3880. if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self)))
  3881. common_process_serving_system_3gpp (self, NULL, output);
  3882. else if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (self)))
  3883. common_process_serving_system_cdma (self, NULL, output);
  3884. }
  3885. static void
  3886. common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self,
  3887. gboolean enable,
  3888. GAsyncReadyCallback callback,
  3889. gpointer user_data)
  3890. {
  3891. GSimpleAsyncResult *result;
  3892. QmiClient *client = NULL;
  3893. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  3894. QMI_SERVICE_NAS, &client,
  3895. callback, user_data))
  3896. return;
  3897. result = g_simple_async_result_new (G_OBJECT (self),
  3898. callback,
  3899. user_data,
  3900. common_setup_cleanup_unsolicited_registration_events);
  3901. if (enable == self->priv->unsolicited_registration_events_setup) {
  3902. mm_dbg ("Unsolicited registration events already %s; skipping",
  3903. enable ? "setup" : "cleanup");
  3904. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  3905. g_simple_async_result_complete_in_idle (result);
  3906. g_object_unref (result);
  3907. return;
  3908. }
  3909. /* Store new state */
  3910. self->priv->unsolicited_registration_events_setup = enable;
  3911. #if defined WITH_NEWEST_QMI_COMMANDS
  3912. /* Signal info introduced in NAS 1.8 */
  3913. if (qmi_client_check_version (client, 1, 8)) {
  3914. /* Connect/Disconnect "System Info" indications */
  3915. if (enable) {
  3916. g_assert (self->priv->system_info_indication_id == 0);
  3917. self->priv->system_info_indication_id =
  3918. g_signal_connect (client,
  3919. "system-info",
  3920. G_CALLBACK (system_info_indication_cb),
  3921. self);
  3922. } else {
  3923. g_assert (self->priv->system_info_indication_id != 0);
  3924. g_signal_handler_disconnect (client, self->priv->system_info_indication_id);
  3925. self->priv->system_info_indication_id = 0;
  3926. }
  3927. } else
  3928. #endif /* WITH_NEWEST_QMI_COMMANDS */
  3929. {
  3930. /* Connect/Disconnect "Serving System" indications */
  3931. if (enable) {
  3932. g_assert (self->priv->serving_system_indication_id == 0);
  3933. self->priv->serving_system_indication_id =
  3934. g_signal_connect (client,
  3935. "serving-system",
  3936. G_CALLBACK (serving_system_indication_cb),
  3937. self);
  3938. } else {
  3939. g_assert (self->priv->serving_system_indication_id != 0);
  3940. g_signal_handler_disconnect (client, self->priv->serving_system_indication_id);
  3941. self->priv->serving_system_indication_id = 0;
  3942. }
  3943. }
  3944. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  3945. g_simple_async_result_complete_in_idle (result);
  3946. g_object_unref (result);
  3947. }
  3948. /*****************************************************************************/
  3949. /* Setup/Cleanup unsolicited registration events (3GPP interface) */
  3950. static gboolean
  3951. modem_3gpp_setup_cleanup_unsolicited_registration_events_finish (MMIfaceModem3gpp *self,
  3952. GAsyncResult *res,
  3953. GError **error)
  3954. { return common_setup_cleanup_unsolicited_registration_events_finish (MM_BROADBAND_MODEM_QMI (self), res, error);
  3955. }
  3956. static void
  3957. modem_3gpp_cleanup_unsolicited_registration_events (MMIfaceModem3gpp *self,
  3958. GAsyncReadyCallback callback,
  3959. gpointer user_data)
  3960. {
  3961. common_setup_cleanup_unsolicited_registration_events (MM_BROADBAND_MODEM_QMI (self),
  3962. FALSE,
  3963. callback,
  3964. user_data);
  3965. }
  3966. static void
  3967. modem_3gpp_setup_unsolicited_registration_events (MMIfaceModem3gpp *self,
  3968. GAsyncReadyCallback callback,
  3969. gpointer user_data)
  3970. {
  3971. common_setup_cleanup_unsolicited_registration_events (MM_BROADBAND_MODEM_QMI (self),
  3972. TRUE,
  3973. callback,
  3974. user_data);
  3975. }
  3976. /*****************************************************************************/
  3977. /* MEID loading (CDMA interface) */
  3978. static gchar *
  3979. modem_cdma_load_meid_finish (MMIfaceModemCdma *self,
  3980. GAsyncResult *res,
  3981. GError **error)
  3982. {
  3983. gchar *meid;
  3984. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  3985. return NULL;
  3986. meid = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  3987. mm_dbg ("loaded MEID: %s", meid);
  3988. return meid;
  3989. }
  3990. static void
  3991. modem_cdma_load_meid (MMIfaceModemCdma *_self,
  3992. GAsyncReadyCallback callback,
  3993. gpointer user_data)
  3994. {
  3995. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  3996. GSimpleAsyncResult *result;
  3997. result = g_simple_async_result_new (G_OBJECT (self),
  3998. callback,
  3999. user_data,
  4000. modem_cdma_load_meid);
  4001. if (self->priv->meid)
  4002. g_simple_async_result_set_op_res_gpointer (result,
  4003. self->priv->meid,
  4004. NULL);
  4005. else
  4006. g_simple_async_result_set_error (result,
  4007. MM_CORE_ERROR,
  4008. MM_CORE_ERROR_FAILED,
  4009. "Device doesn't report a valid MEID");
  4010. g_simple_async_result_complete_in_idle (result);
  4011. g_object_unref (result);
  4012. }
  4013. /*****************************************************************************/
  4014. /* ESN loading (CDMA interface) */
  4015. static gchar *
  4016. modem_cdma_load_esn_finish (MMIfaceModemCdma *self,
  4017. GAsyncResult *res,
  4018. GError **error)
  4019. {
  4020. gchar *esn;
  4021. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  4022. return NULL;
  4023. esn = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
  4024. mm_dbg ("loaded ESN: %s", esn);
  4025. return esn;
  4026. }
  4027. static void
  4028. modem_cdma_load_esn (MMIfaceModemCdma *_self,
  4029. GAsyncReadyCallback callback,
  4030. gpointer user_data)
  4031. {
  4032. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  4033. GSimpleAsyncResult *result;
  4034. result = g_simple_async_result_new (G_OBJECT (self),
  4035. callback,
  4036. user_data,
  4037. modem_cdma_load_esn);
  4038. if (self->priv->esn)
  4039. g_simple_async_result_set_op_res_gpointer (result,
  4040. self->priv->esn,
  4041. NULL);
  4042. else
  4043. g_simple_async_result_set_error (result,
  4044. MM_CORE_ERROR,
  4045. MM_CORE_ERROR_FAILED,
  4046. "Device doesn't report a valid ESN");
  4047. g_simple_async_result_complete_in_idle (result);
  4048. g_object_unref (result);
  4049. }
  4050. /*****************************************************************************/
  4051. /* Enabling/disabling unsolicited events (3GPP and CDMA interface)
  4052. *
  4053. * If NAS >= 1.8:
  4054. * - Config Signal Info (only when enabling)
  4055. * - Register Indications with Signal Info
  4056. *
  4057. * If NAS < 1.8:
  4058. * - Set Event Report with Signal Strength
  4059. */
  4060. typedef struct {
  4061. MMBroadbandModemQmi *self;
  4062. GSimpleAsyncResult *result;
  4063. QmiClientNas *client;
  4064. gboolean enable;
  4065. } EnableUnsolicitedEventsContext;
  4066. static void
  4067. enable_unsolicited_events_context_complete_and_free (EnableUnsolicitedEventsContext *ctx)
  4068. {
  4069. g_simple_async_result_complete (ctx->result);
  4070. g_object_unref (ctx->result);
  4071. g_object_unref (ctx->client);
  4072. g_object_unref (ctx->self);
  4073. g_free (ctx);
  4074. }
  4075. static gboolean
  4076. common_enable_disable_unsolicited_events_finish (MMBroadbandModemQmi *self,
  4077. GAsyncResult *res,
  4078. GError **error)
  4079. {
  4080. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  4081. }
  4082. static void
  4083. ser_signal_strength_ready (QmiClientNas *client,
  4084. GAsyncResult *res,
  4085. EnableUnsolicitedEventsContext *ctx)
  4086. {
  4087. QmiMessageNasSetEventReportOutput *output = NULL;
  4088. GError *error = NULL;
  4089. output = qmi_client_nas_set_event_report_finish (client, res, &error);
  4090. if (!output) {
  4091. mm_dbg ("QMI operation failed: '%s'", error->message);
  4092. g_error_free (error);
  4093. } else if (!qmi_message_nas_set_event_report_output_get_result (output, &error)) {
  4094. mm_dbg ("Couldn't set event report: '%s'", error->message);
  4095. g_error_free (error);
  4096. }
  4097. if (output)
  4098. qmi_message_nas_set_event_report_output_unref (output);
  4099. /* Just ignore errors for now */
  4100. ctx->self->priv->unsolicited_events_enabled = ctx->enable;
  4101. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  4102. enable_unsolicited_events_context_complete_and_free (ctx);
  4103. }
  4104. static void
  4105. common_enable_disable_unsolicited_events_signal_strength (EnableUnsolicitedEventsContext *ctx)
  4106. {
  4107. /* The device doesn't really like to have many threshold values, so don't
  4108. * grow this array without checking first */
  4109. static const gint8 thresholds_data[] = { -80, -40, 0, 40, 80 };
  4110. QmiMessageNasSetEventReportInput *input;
  4111. GArray *thresholds;
  4112. input = qmi_message_nas_set_event_report_input_new ();
  4113. /* Prepare thresholds, separated 20 each */
  4114. thresholds = g_array_sized_new (FALSE, FALSE, sizeof (gint8), G_N_ELEMENTS (thresholds_data));
  4115. /* Only set thresholds during enable */
  4116. if (ctx->enable)
  4117. g_array_append_vals (thresholds, thresholds_data, G_N_ELEMENTS (thresholds_data));
  4118. qmi_message_nas_set_event_report_input_set_signal_strength_indicator (
  4119. input,
  4120. ctx->enable,
  4121. thresholds,
  4122. NULL);
  4123. g_array_unref (thresholds);
  4124. qmi_client_nas_set_event_report (
  4125. ctx->client,
  4126. input,
  4127. 5,
  4128. NULL,
  4129. (GAsyncReadyCallback)ser_signal_strength_ready,
  4130. ctx);
  4131. qmi_message_nas_set_event_report_input_unref (input);
  4132. }
  4133. #if defined WITH_NEWEST_QMI_COMMANDS
  4134. static void
  4135. ri_signal_info_ready (QmiClientNas *client,
  4136. GAsyncResult *res,
  4137. EnableUnsolicitedEventsContext *ctx)
  4138. {
  4139. QmiMessageNasRegisterIndicationsOutput *output = NULL;
  4140. GError *error = NULL;
  4141. output = qmi_client_nas_register_indications_finish (client, res, &error);
  4142. if (!output) {
  4143. mm_dbg ("QMI operation failed: '%s'", error->message);
  4144. g_error_free (error);
  4145. } else if (!qmi_message_nas_register_indications_output_get_result (output, &error)) {
  4146. mm_dbg ("Couldn't register indications: '%s'", error->message);
  4147. g_error_free (error);
  4148. }
  4149. if (output)
  4150. qmi_message_nas_register_indications_output_unref (output);
  4151. /* Just ignore errors for now */
  4152. ctx->self->priv->unsolicited_events_enabled = ctx->enable;
  4153. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  4154. enable_unsolicited_events_context_complete_and_free (ctx);
  4155. }
  4156. static void
  4157. common_enable_disable_unsolicited_events_signal_info (EnableUnsolicitedEventsContext *ctx)
  4158. {
  4159. QmiMessageNasRegisterIndicationsInput *input;
  4160. input = qmi_message_nas_register_indications_input_new ();
  4161. qmi_message_nas_register_indications_input_set_signal_info (input, ctx->enable, NULL);
  4162. qmi_client_nas_register_indications (
  4163. ctx->client,
  4164. input,
  4165. 5,
  4166. NULL,
  4167. (GAsyncReadyCallback)ri_signal_info_ready,
  4168. ctx);
  4169. qmi_message_nas_register_indications_input_unref (input);
  4170. }
  4171. static void
  4172. config_signal_info_ready (QmiClientNas *client,
  4173. GAsyncResult *res,
  4174. EnableUnsolicitedEventsContext *ctx)
  4175. {
  4176. QmiMessageNasConfigSignalInfoOutput *output = NULL;
  4177. GError *error = NULL;
  4178. output = qmi_client_nas_config_signal_info_finish (client, res, &error);
  4179. if (!output) {
  4180. mm_dbg ("QMI operation failed: '%s'", error->message);
  4181. g_error_free (error);
  4182. } else if (!qmi_message_nas_config_signal_info_output_get_result (output, &error)) {
  4183. mm_dbg ("Couldn't config signal info: '%s'", error->message);
  4184. g_error_free (error);
  4185. }
  4186. if (output)
  4187. qmi_message_nas_config_signal_info_output_unref (output);
  4188. /* Keep on */
  4189. common_enable_disable_unsolicited_events_signal_info (ctx);
  4190. }
  4191. static void
  4192. common_enable_disable_unsolicited_events_signal_info_config (EnableUnsolicitedEventsContext *ctx)
  4193. {
  4194. /* RSSI values go between -105 and -60 for 3GPP technologies,
  4195. * and from -105 to -90 in 3GPP2 technologies (approx). */
  4196. static const gint8 thresholds_data[] = { -100, -97, -95, -92, -90, -85, -80, -75, -70, -65 };
  4197. QmiMessageNasConfigSignalInfoInput *input;
  4198. GArray *thresholds;
  4199. /* Signal info config only to be run when enabling */
  4200. if (!ctx->enable) {
  4201. common_enable_disable_unsolicited_events_signal_info (ctx);
  4202. return;
  4203. }
  4204. input = qmi_message_nas_config_signal_info_input_new ();
  4205. /* Prepare thresholds, separated 20 each */
  4206. thresholds = g_array_sized_new (FALSE, FALSE, sizeof (gint8), G_N_ELEMENTS (thresholds_data));
  4207. g_array_append_vals (thresholds, thresholds_data, G_N_ELEMENTS (thresholds_data));
  4208. qmi_message_nas_config_signal_info_input_set_rssi_threshold (
  4209. input,
  4210. thresholds,
  4211. NULL);
  4212. g_array_unref (thresholds);
  4213. qmi_client_nas_config_signal_info (
  4214. ctx->client,
  4215. input,
  4216. 5,
  4217. NULL,
  4218. (GAsyncReadyCallback)config_signal_info_ready,
  4219. ctx);
  4220. qmi_message_nas_config_signal_info_input_unref (input);
  4221. }
  4222. #endif /* WITH_NEWEST_QMI_COMMANDS */
  4223. static void
  4224. common_enable_disable_unsolicited_events (MMBroadbandModemQmi *self,
  4225. gboolean enable,
  4226. GAsyncReadyCallback callback,
  4227. gpointer user_data)
  4228. {
  4229. EnableUnsolicitedEventsContext *ctx;
  4230. GSimpleAsyncResult *result;
  4231. QmiClient *client = NULL;
  4232. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  4233. QMI_SERVICE_NAS, &client,
  4234. callback, user_data))
  4235. return;
  4236. result = g_simple_async_result_new (G_OBJECT (self),
  4237. callback,
  4238. user_data,
  4239. common_enable_disable_unsolicited_events);
  4240. if (enable == self->priv->unsolicited_events_enabled) {
  4241. mm_dbg ("Unsolicited events already %s; skipping",
  4242. enable ? "enabled" : "disabled");
  4243. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  4244. g_simple_async_result_complete_in_idle (result);
  4245. g_object_unref (result);
  4246. return;
  4247. }
  4248. ctx = g_new0 (EnableUnsolicitedEventsContext, 1);
  4249. ctx->self = g_object_ref (self);
  4250. ctx->client = g_object_ref (client);
  4251. ctx->enable = enable;
  4252. ctx->result = result;
  4253. #if defined WITH_NEWEST_QMI_COMMANDS
  4254. /* Signal info introduced in NAS 1.8 */
  4255. if (qmi_client_check_version (client, 1, 8)) {
  4256. common_enable_disable_unsolicited_events_signal_info_config (ctx);
  4257. return;
  4258. }
  4259. #endif /* WITH_NEWEST_QMI_COMMANDS */
  4260. common_enable_disable_unsolicited_events_signal_strength (ctx);
  4261. }
  4262. /*****************************************************************************/
  4263. /* Enable/Disable unsolicited events (3GPP interface) */
  4264. static gboolean
  4265. modem_3gpp_enable_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
  4266. GAsyncResult *res,
  4267. GError **error)
  4268. {
  4269. return common_enable_disable_unsolicited_events_finish (MM_BROADBAND_MODEM_QMI (self), res, error);
  4270. }
  4271. static void
  4272. modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
  4273. GAsyncReadyCallback callback,
  4274. gpointer user_data)
  4275. {
  4276. common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4277. FALSE,
  4278. callback,
  4279. user_data);
  4280. }
  4281. static void
  4282. modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
  4283. GAsyncReadyCallback callback,
  4284. gpointer user_data)
  4285. {
  4286. common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4287. TRUE,
  4288. callback,
  4289. user_data);
  4290. }
  4291. /*****************************************************************************/
  4292. /* Enable/Disable unsolicited events (CDMA interface) */
  4293. static gboolean
  4294. modem_cdma_enable_disable_unsolicited_events_finish (MMIfaceModemCdma *self,
  4295. GAsyncResult *res,
  4296. GError **error)
  4297. {
  4298. return common_enable_disable_unsolicited_events_finish (MM_BROADBAND_MODEM_QMI (self), res, error);
  4299. }
  4300. static void
  4301. modem_cdma_disable_unsolicited_events (MMIfaceModemCdma *self,
  4302. GAsyncReadyCallback callback,
  4303. gpointer user_data)
  4304. {
  4305. common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4306. FALSE,
  4307. callback,
  4308. user_data);
  4309. }
  4310. static void
  4311. modem_cdma_enable_unsolicited_events (MMIfaceModemCdma *self,
  4312. GAsyncReadyCallback callback,
  4313. gpointer user_data)
  4314. {
  4315. common_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4316. TRUE,
  4317. callback,
  4318. user_data);
  4319. }
  4320. /*****************************************************************************/
  4321. /* Setup/Cleanup unsolicited event handlers (3GPP and CDMA interface) */
  4322. static gboolean
  4323. common_setup_cleanup_unsolicited_events_finish (MMBroadbandModemQmi *self,
  4324. GAsyncResult *res,
  4325. GError **error)
  4326. {
  4327. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  4328. }
  4329. static void
  4330. event_report_indication_cb (QmiClientNas *client,
  4331. QmiIndicationNasEventReportOutput *output,
  4332. MMBroadbandModemQmi *self)
  4333. {
  4334. gint8 signal_strength;
  4335. QmiNasRadioInterface signal_strength_radio_interface;
  4336. if (qmi_indication_nas_event_report_output_get_signal_strength (
  4337. output,
  4338. &signal_strength,
  4339. &signal_strength_radio_interface,
  4340. NULL)) {
  4341. guint8 quality;
  4342. /* This signal strength comes as negative dBms */
  4343. quality = STRENGTH_TO_QUALITY (signal_strength);
  4344. mm_dbg ("Signal strength indication (%s): %d dBm --> %u%%",
  4345. qmi_nas_radio_interface_get_string (signal_strength_radio_interface),
  4346. signal_strength,
  4347. quality);
  4348. mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality);
  4349. mm_iface_modem_update_access_technologies (
  4350. MM_IFACE_MODEM (self),
  4351. mm_modem_access_technology_from_qmi_radio_interface (signal_strength_radio_interface),
  4352. (MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK | MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK));
  4353. }
  4354. }
  4355. #if defined WITH_NEWEST_QMI_COMMANDS
  4356. static void
  4357. signal_info_indication_cb (QmiClientNas *client,
  4358. QmiIndicationNasSignalInfoOutput *output,
  4359. MMBroadbandModemQmi *self)
  4360. {
  4361. gint8 rssi_max = 0;
  4362. gint8 rssi;
  4363. guint8 quality;
  4364. /* We do not report per-technology signal quality, so just get the highest
  4365. * one of the ones reported. TODO: When several technologies are in use, if
  4366. * the indication only contains the data of the one which passed a threshold
  4367. * value, we'll need to have an internal cache of per-technology values, in
  4368. * order to report always the one with the maximum value. */
  4369. if (qmi_indication_nas_signal_info_output_get_cdma_signal_strength (output, &rssi, NULL, NULL)) {
  4370. mm_dbg ("RSSI (CDMA): %d dBm", rssi);
  4371. rssi = MAX (rssi, rssi_max);
  4372. }
  4373. if (qmi_indication_nas_signal_info_output_get_hdr_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) {
  4374. mm_dbg ("RSSI (HDR): %d dBm", rssi);
  4375. rssi = MAX (rssi, rssi_max);
  4376. }
  4377. if (qmi_indication_nas_signal_info_output_get_gsm_signal_strength (output, &rssi, NULL)) {
  4378. mm_dbg ("RSSI (GSM): %d dBm", rssi);
  4379. rssi = MAX (rssi, rssi_max);
  4380. }
  4381. if (qmi_indication_nas_signal_info_output_get_wcdma_signal_strength (output, &rssi, NULL, NULL)) {
  4382. mm_dbg ("RSSI (WCDMA): %d dBm", rssi);
  4383. rssi = MAX (rssi, rssi_max);
  4384. }
  4385. if (qmi_indication_nas_signal_info_output_get_lte_signal_strength (output, &rssi, NULL, NULL, NULL, NULL)) {
  4386. mm_dbg ("RSSI (LTE): %d dBm", rssi);
  4387. rssi = MAX (rssi, rssi_max);
  4388. }
  4389. /* This RSSI comes as negative dBms */
  4390. quality = STRENGTH_TO_QUALITY (rssi_max);
  4391. mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, quality);
  4392. mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality);
  4393. }
  4394. #endif /* WITH_NEWEST_QMI_COMMANDS */
  4395. static void
  4396. common_setup_cleanup_unsolicited_events (MMBroadbandModemQmi *self,
  4397. gboolean enable,
  4398. GAsyncReadyCallback callback,
  4399. gpointer user_data)
  4400. {
  4401. GSimpleAsyncResult *result;
  4402. QmiClient *client = NULL;
  4403. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  4404. QMI_SERVICE_NAS, &client,
  4405. callback, user_data))
  4406. return;
  4407. result = g_simple_async_result_new (G_OBJECT (self),
  4408. callback,
  4409. user_data,
  4410. common_enable_disable_unsolicited_events);
  4411. if (enable == self->priv->unsolicited_events_setup) {
  4412. mm_dbg ("Unsolicited events already %s; skipping",
  4413. enable ? "setup" : "cleanup");
  4414. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  4415. g_simple_async_result_complete_in_idle (result);
  4416. g_object_unref (result);
  4417. return;
  4418. }
  4419. /* Store new state */
  4420. self->priv->unsolicited_events_setup = enable;
  4421. /* Connect/Disconnect "Event Report" indications */
  4422. if (enable) {
  4423. g_assert (self->priv->event_report_indication_id == 0);
  4424. self->priv->event_report_indication_id =
  4425. g_signal_connect (client,
  4426. "event-report",
  4427. G_CALLBACK (event_report_indication_cb),
  4428. self);
  4429. } else {
  4430. g_assert (self->priv->event_report_indication_id != 0);
  4431. g_signal_handler_disconnect (client, self->priv->event_report_indication_id);
  4432. self->priv->event_report_indication_id = 0;
  4433. }
  4434. #if defined WITH_NEWEST_QMI_COMMANDS
  4435. /* Connect/Disconnect "Signal Info" indications.
  4436. * Signal info introduced in NAS 1.8 */
  4437. if (qmi_client_check_version (client, 1, 8)) {
  4438. if (enable) {
  4439. g_assert (self->priv->signal_info_indication_id == 0);
  4440. self->priv->signal_info_indication_id =
  4441. g_signal_connect (client,
  4442. "signal-info",
  4443. G_CALLBACK (signal_info_indication_cb),
  4444. self);
  4445. } else {
  4446. g_assert (self->priv->signal_info_indication_id != 0);
  4447. g_signal_handler_disconnect (client, self->priv->signal_info_indication_id);
  4448. self->priv->signal_info_indication_id = 0;
  4449. }
  4450. }
  4451. #endif /* WITH_NEWEST_QMI_COMMANDS */
  4452. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  4453. g_simple_async_result_complete_in_idle (result);
  4454. g_object_unref (result);
  4455. }
  4456. /*****************************************************************************/
  4457. /* Enable/Disable unsolicited events (3GPP interface) */
  4458. static gboolean
  4459. modem_3gpp_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gpp *self,
  4460. GAsyncResult *res,
  4461. GError **error)
  4462. {
  4463. return common_setup_cleanup_unsolicited_events_finish (MM_BROADBAND_MODEM_QMI (self), res, error);
  4464. }
  4465. static void
  4466. modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self,
  4467. GAsyncReadyCallback callback,
  4468. gpointer user_data)
  4469. {
  4470. common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4471. FALSE,
  4472. callback,
  4473. user_data);
  4474. }
  4475. static void
  4476. modem_3gpp_setup_unsolicited_events (MMIfaceModem3gpp *self,
  4477. GAsyncReadyCallback callback,
  4478. gpointer user_data)
  4479. {
  4480. common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4481. TRUE,
  4482. callback,
  4483. user_data);
  4484. }
  4485. /*****************************************************************************/
  4486. /* Enable/Disable unsolicited events (CDMA interface) */
  4487. static gboolean
  4488. modem_cdma_setup_cleanup_unsolicited_events_finish (MMIfaceModemCdma *self,
  4489. GAsyncResult *res,
  4490. GError **error)
  4491. {
  4492. return common_setup_cleanup_unsolicited_events_finish (MM_BROADBAND_MODEM_QMI (self), res, error);
  4493. }
  4494. static void
  4495. modem_cdma_cleanup_unsolicited_events (MMIfaceModemCdma *self,
  4496. GAsyncReadyCallback callback,
  4497. gpointer user_data)
  4498. {
  4499. common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4500. FALSE,
  4501. callback,
  4502. user_data);
  4503. }
  4504. static void
  4505. modem_cdma_setup_unsolicited_events (MMIfaceModemCdma *self,
  4506. GAsyncReadyCallback callback,
  4507. gpointer user_data)
  4508. {
  4509. common_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  4510. TRUE,
  4511. callback,
  4512. user_data);
  4513. }
  4514. /*****************************************************************************/
  4515. /* Check support (Messaging interface) */
  4516. static gboolean
  4517. messaging_check_support_finish (MMIfaceModemMessaging *self,
  4518. GAsyncResult *res,
  4519. GError **error)
  4520. {
  4521. /* no error expected here */
  4522. return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res));
  4523. }
  4524. static void
  4525. messaging_check_support (MMIfaceModemMessaging *self,
  4526. GAsyncReadyCallback callback,
  4527. gpointer user_data)
  4528. {
  4529. GSimpleAsyncResult *result;
  4530. gboolean supported;
  4531. MMQmiPort *port;
  4532. result = g_simple_async_result_new (G_OBJECT (self),
  4533. callback,
  4534. user_data,
  4535. messaging_check_support);
  4536. port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
  4537. if (!port)
  4538. supported = FALSE;
  4539. else
  4540. /* If we have support for the WMS client, messaging is supported */
  4541. supported = !!mm_qmi_port_peek_client (port,
  4542. QMI_SERVICE_WMS,
  4543. MM_QMI_PORT_FLAG_DEFAULT);
  4544. /* We only handle 3GPP messaging (PDU based) currently, so just ignore
  4545. * CDMA-only QMI modems */
  4546. if (mm_iface_modem_is_cdma_only (MM_IFACE_MODEM (self)) && supported) {
  4547. mm_dbg ("Messaging capabilities supported by this modem, "
  4548. "but 3GPP2 messaging not supported yet by ModemManager");
  4549. supported = FALSE;
  4550. } else
  4551. mm_dbg ("Messaging capabilities %s by this modem",
  4552. supported ? "supported" : "not supported");
  4553. g_simple_async_result_set_op_res_gboolean (result, supported);
  4554. g_simple_async_result_complete_in_idle (result);
  4555. g_object_unref (result);
  4556. }
  4557. /*****************************************************************************/
  4558. /* Load supported storages (Messaging interface) */
  4559. static gboolean
  4560. messaging_load_supported_storages_finish (MMIfaceModemMessaging *self,
  4561. GAsyncResult *res,
  4562. GArray **mem1,
  4563. GArray **mem2,
  4564. GArray **mem3,
  4565. GError **error)
  4566. {
  4567. MMSmsStorage supported [2] = { MM_SMS_STORAGE_SM, MM_SMS_STORAGE_ME };
  4568. *mem1 = g_array_append_vals (g_array_sized_new (FALSE, FALSE, sizeof (MMSmsStorage), 2),
  4569. supported, 2);
  4570. *mem2 = g_array_ref (*mem1);
  4571. *mem3 = g_array_ref (*mem1);
  4572. return TRUE;
  4573. }
  4574. static void
  4575. messaging_load_supported_storages (MMIfaceModemMessaging *self,
  4576. GAsyncReadyCallback callback,
  4577. gpointer user_data)
  4578. {
  4579. GSimpleAsyncResult *result;
  4580. result = g_simple_async_result_new (G_OBJECT (self),
  4581. callback,
  4582. user_data,
  4583. messaging_load_supported_storages);
  4584. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  4585. g_simple_async_result_complete_in_idle (result);
  4586. g_object_unref (result);
  4587. }
  4588. /*****************************************************************************/
  4589. /* Set default storage (Messaging interface) */
  4590. static gboolean
  4591. messaging_set_default_storage_finish (MMIfaceModemMessaging *self,
  4592. GAsyncResult *res,
  4593. GError **error)
  4594. {
  4595. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  4596. }
  4597. static void
  4598. wms_set_routes_ready (QmiClientWms *client,
  4599. GAsyncResult *res,
  4600. GSimpleAsyncResult *simple)
  4601. {
  4602. QmiMessageWmsSetRoutesOutput *output = NULL;
  4603. GError *error = NULL;
  4604. output = qmi_client_wms_set_routes_finish (client, res, &error);
  4605. if (!output) {
  4606. g_prefix_error (&error, "QMI operation failed: ");
  4607. g_simple_async_result_take_error (simple, error);
  4608. } else if (!qmi_message_wms_set_routes_output_get_result (output, &error)) {
  4609. g_prefix_error (&error, "Couldn't set routes: ");
  4610. g_simple_async_result_take_error (simple, error);
  4611. } else {
  4612. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  4613. }
  4614. if (output)
  4615. qmi_message_wms_set_routes_output_unref (output);
  4616. g_simple_async_result_complete (simple);
  4617. g_object_unref (simple);
  4618. }
  4619. static void
  4620. messaging_set_default_storage (MMIfaceModemMessaging *self,
  4621. MMSmsStorage storage,
  4622. GAsyncReadyCallback callback,
  4623. gpointer user_data)
  4624. {
  4625. GSimpleAsyncResult *result;
  4626. QmiClient *client = NULL;
  4627. QmiMessageWmsSetRoutesInput *input;
  4628. GArray *routes_array;
  4629. QmiMessageWmsSetRoutesInputRouteListElement route;
  4630. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  4631. QMI_SERVICE_WMS, &client,
  4632. callback, user_data))
  4633. return;
  4634. result = g_simple_async_result_new (G_OBJECT (self),
  4635. callback,
  4636. user_data,
  4637. messaging_set_default_storage);
  4638. /* Build routes array and add it as input
  4639. * Just worry about Class 0 and Class 1 messages for now */
  4640. input = qmi_message_wms_set_routes_input_new ();
  4641. routes_array = g_array_sized_new (FALSE, FALSE, sizeof (route), 2);
  4642. route.message_type = QMI_WMS_MESSAGE_TYPE_POINT_TO_POINT;
  4643. route.message_class = QMI_WMS_MESSAGE_CLASS_0;
  4644. route.storage = mm_sms_storage_to_qmi_storage_type (storage);
  4645. route.receipt_action = QMI_WMS_RECEIPT_ACTION_STORE_AND_NOTIFY;
  4646. g_array_append_val (routes_array, route);
  4647. route.message_class = QMI_WMS_MESSAGE_CLASS_1;
  4648. g_array_append_val (routes_array, route);
  4649. qmi_message_wms_set_routes_input_set_route_list (input, routes_array, NULL);
  4650. mm_dbg ("setting default messaging routes...");
  4651. qmi_client_wms_set_routes (QMI_CLIENT_WMS (client),
  4652. input,
  4653. 5,
  4654. NULL,
  4655. (GAsyncReadyCallback)wms_set_routes_ready,
  4656. result);
  4657. qmi_message_wms_set_routes_input_unref (input);
  4658. g_array_unref (routes_array);
  4659. }
  4660. /*****************************************************************************/
  4661. /* Load initial SMS parts */
  4662. typedef struct {
  4663. MMBroadbandModemQmi *self;
  4664. GSimpleAsyncResult *result;
  4665. QmiClientWms *client;
  4666. MMSmsStorage storage;
  4667. GArray *message_array;
  4668. guint i;
  4669. } LoadInitialSmsPartsContext;
  4670. static void
  4671. load_initial_sms_parts_context_complete_and_free (LoadInitialSmsPartsContext *ctx)
  4672. {
  4673. g_simple_async_result_complete (ctx->result);
  4674. g_object_unref (ctx->result);
  4675. if (ctx->message_array)
  4676. g_array_unref (ctx->message_array);
  4677. g_object_unref (ctx->client);
  4678. g_object_unref (ctx->self);
  4679. g_slice_free (LoadInitialSmsPartsContext, ctx);
  4680. }
  4681. static gboolean
  4682. load_initial_sms_parts_finish (MMIfaceModemMessaging *self,
  4683. GAsyncResult *res,
  4684. GError **error)
  4685. {
  4686. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  4687. }
  4688. static void read_next_sms_part (LoadInitialSmsPartsContext *ctx);
  4689. static void
  4690. add_new_read_sms_part (MMIfaceModemMessaging *self,
  4691. QmiWmsStorageType storage,
  4692. guint32 index,
  4693. QmiWmsMessageTagType tag,
  4694. QmiWmsMessageFormat format,
  4695. GArray *data)
  4696. {
  4697. switch (format) {
  4698. case QMI_WMS_MESSAGE_FORMAT_CDMA:
  4699. mm_dbg ("Skipping CDMA messages for now...");
  4700. break;
  4701. case QMI_WMS_MESSAGE_FORMAT_MWI:
  4702. mm_dbg ("Don't know how to process 'message waiting indicator' messages");
  4703. break;
  4704. case QMI_WMS_MESSAGE_FORMAT_GSM_WCDMA_POINT_TO_POINT:
  4705. case QMI_WMS_MESSAGE_FORMAT_GSM_WCDMA_BROADCAST: {
  4706. MMSmsPart *part;
  4707. GError *error = NULL;
  4708. part = mm_sms_part_new_from_binary_pdu (index,
  4709. (guint8 *)data->data,
  4710. data->len,
  4711. &error);
  4712. if (part) {
  4713. mm_dbg ("Correctly parsed PDU (%d)",
  4714. index);
  4715. mm_iface_modem_messaging_take_part (self,
  4716. part,
  4717. mm_sms_state_from_qmi_message_tag (tag),
  4718. mm_sms_storage_from_qmi_storage_type (storage));
  4719. } else {
  4720. /* Don't treat the error as critical */
  4721. mm_dbg ("Error parsing PDU (%d): %s",
  4722. index,
  4723. error->message);
  4724. g_error_free (error);
  4725. }
  4726. break;
  4727. }
  4728. default:
  4729. mm_dbg ("Unhandled message format '%u'", format);
  4730. break;
  4731. }
  4732. }
  4733. static void
  4734. wms_raw_read_ready (QmiClientWms *client,
  4735. GAsyncResult *res,
  4736. LoadInitialSmsPartsContext *ctx)
  4737. {
  4738. QmiMessageWmsRawReadOutput *output = NULL;
  4739. GError *error = NULL;
  4740. /* Ignore errors, just keep on with the next messages */
  4741. output = qmi_client_wms_raw_read_finish (client, res, &error);
  4742. if (!output) {
  4743. mm_dbg ("QMI operation failed: %s", error->message);
  4744. g_error_free (error);
  4745. } else if (!qmi_message_wms_raw_read_output_get_result (output, &error)) {
  4746. mm_dbg ("Couldn't read raw message: %s", error->message);
  4747. g_error_free (error);
  4748. } else {
  4749. QmiWmsMessageTagType tag;
  4750. QmiWmsMessageFormat format;
  4751. GArray *data;
  4752. QmiMessageWmsListMessagesOutputMessageListElement *message;
  4753. message = &g_array_index (ctx->message_array,
  4754. QmiMessageWmsListMessagesOutputMessageListElement,
  4755. ctx->i);
  4756. qmi_message_wms_raw_read_output_get_raw_message_data (
  4757. output,
  4758. &tag,
  4759. &format,
  4760. &data,
  4761. NULL);
  4762. add_new_read_sms_part (MM_IFACE_MODEM_MESSAGING (ctx->self),
  4763. mm_sms_storage_to_qmi_storage_type (ctx->storage),
  4764. message->memory_index,
  4765. tag,
  4766. format,
  4767. data);
  4768. }
  4769. if (output)
  4770. qmi_message_wms_raw_read_output_unref (output);
  4771. /* Keep on reading parts */
  4772. ctx->i++;
  4773. read_next_sms_part (ctx);
  4774. }
  4775. static void
  4776. read_next_sms_part (LoadInitialSmsPartsContext *ctx)
  4777. {
  4778. QmiMessageWmsListMessagesOutputMessageListElement *message;
  4779. QmiMessageWmsRawReadInput *input;
  4780. if (ctx->i >= ctx->message_array->len ||
  4781. !ctx->message_array) {
  4782. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  4783. load_initial_sms_parts_context_complete_and_free (ctx);
  4784. return;
  4785. }
  4786. message = &g_array_index (ctx->message_array,
  4787. QmiMessageWmsListMessagesOutputMessageListElement,
  4788. ctx->i);
  4789. input = qmi_message_wms_raw_read_input_new ();
  4790. qmi_message_wms_raw_read_input_set_message_memory_storage_id (
  4791. input,
  4792. mm_sms_storage_to_qmi_storage_type (ctx->storage),
  4793. message->memory_index,
  4794. NULL);
  4795. qmi_client_wms_raw_read (QMI_CLIENT_WMS (ctx->client),
  4796. input,
  4797. 3,
  4798. NULL,
  4799. (GAsyncReadyCallback)wms_raw_read_ready,
  4800. ctx);
  4801. qmi_message_wms_raw_read_input_unref (input);
  4802. }
  4803. static void
  4804. wms_list_messages_ready (QmiClientWms *client,
  4805. GAsyncResult *res,
  4806. LoadInitialSmsPartsContext *ctx)
  4807. {
  4808. QmiMessageWmsListMessagesOutput *output = NULL;
  4809. GError *error = NULL;
  4810. GArray *message_array;
  4811. output = qmi_client_wms_list_messages_finish (client, res, &error);
  4812. if (!output) {
  4813. g_prefix_error (&error, "QMI operation failed: ");
  4814. g_simple_async_result_take_error (ctx->result, error);
  4815. load_initial_sms_parts_context_complete_and_free (ctx);
  4816. return;
  4817. }
  4818. if (!qmi_message_wms_list_messages_output_get_result (output, &error)) {
  4819. g_prefix_error (&error, "Couldn't list messages: ");
  4820. g_simple_async_result_take_error (ctx->result, error);
  4821. load_initial_sms_parts_context_complete_and_free (ctx);
  4822. qmi_message_wms_list_messages_output_unref (output);
  4823. return;
  4824. }
  4825. qmi_message_wms_list_messages_output_get_message_list (
  4826. output,
  4827. &message_array,
  4828. NULL);
  4829. /* Keep a reference to the array ourselves */
  4830. ctx->message_array = g_array_ref (message_array);
  4831. qmi_message_wms_list_messages_output_unref (output);
  4832. /* Start reading parts */
  4833. ctx->i = 0;
  4834. read_next_sms_part (ctx);
  4835. }
  4836. static void
  4837. load_initial_sms_parts (MMIfaceModemMessaging *self,
  4838. MMSmsStorage storage,
  4839. GAsyncReadyCallback callback,
  4840. gpointer user_data)
  4841. {
  4842. LoadInitialSmsPartsContext *ctx;
  4843. QmiClient *client = NULL;
  4844. QmiMessageWmsListMessagesInput *input;
  4845. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  4846. QMI_SERVICE_WMS, &client,
  4847. callback, user_data))
  4848. return;
  4849. ctx = g_slice_new0 (LoadInitialSmsPartsContext);
  4850. ctx->self = g_object_ref (self);
  4851. ctx->client = g_object_ref (client);
  4852. ctx->storage = storage;
  4853. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  4854. callback,
  4855. user_data,
  4856. load_initial_sms_parts);
  4857. mm_dbg ("loading messages from storage '%s'...",
  4858. mm_sms_storage_get_string (storage));
  4859. /* Request to list messages in a given storage */
  4860. input = qmi_message_wms_list_messages_input_new ();
  4861. qmi_message_wms_list_messages_input_set_storage_type (
  4862. input,
  4863. mm_sms_storage_to_qmi_storage_type (storage),
  4864. NULL);
  4865. qmi_message_wms_list_messages_input_set_message_mode (
  4866. input,
  4867. QMI_WMS_MESSAGE_MODE_GSM_WCDMA,
  4868. NULL);
  4869. qmi_client_wms_list_messages (QMI_CLIENT_WMS (ctx->client),
  4870. input,
  4871. 5,
  4872. NULL,
  4873. (GAsyncReadyCallback)wms_list_messages_ready,
  4874. ctx);
  4875. qmi_message_wms_list_messages_input_unref (input);
  4876. }
  4877. /*****************************************************************************/
  4878. /* Setup/Cleanup unsolicited event handlers (Messaging interface) */
  4879. typedef struct {
  4880. MMIfaceModemMessaging *self;
  4881. QmiClientWms *client;
  4882. QmiWmsStorageType storage;
  4883. guint32 memory_index;
  4884. } IndicationRawReadContext;
  4885. static void
  4886. indication_raw_read_context_free (IndicationRawReadContext *ctx)
  4887. {
  4888. g_object_unref (ctx->client);
  4889. g_object_unref (ctx->self);
  4890. g_slice_free (IndicationRawReadContext, ctx);
  4891. }
  4892. static void
  4893. wms_indication_raw_read_ready (QmiClientWms *client,
  4894. GAsyncResult *res,
  4895. IndicationRawReadContext *ctx)
  4896. {
  4897. QmiMessageWmsRawReadOutput *output = NULL;
  4898. GError *error = NULL;
  4899. /* Ignore errors */
  4900. output = qmi_client_wms_raw_read_finish (client, res, &error);
  4901. if (!output) {
  4902. mm_dbg ("QMI operation failed: %s", error->message);
  4903. g_error_free (error);
  4904. } else if (!qmi_message_wms_raw_read_output_get_result (output, &error)) {
  4905. mm_dbg ("Couldn't read raw message: %s", error->message);
  4906. g_error_free (error);
  4907. } else {
  4908. QmiWmsMessageTagType tag;
  4909. QmiWmsMessageFormat format;
  4910. GArray *data;
  4911. qmi_message_wms_raw_read_output_get_raw_message_data (
  4912. output,
  4913. &tag,
  4914. &format,
  4915. &data,
  4916. NULL);
  4917. add_new_read_sms_part (MM_IFACE_MODEM_MESSAGING (ctx->self),
  4918. ctx->storage,
  4919. ctx->memory_index,
  4920. tag,
  4921. format,
  4922. data);
  4923. }
  4924. if (output)
  4925. qmi_message_wms_raw_read_output_unref (output);
  4926. indication_raw_read_context_free (ctx);
  4927. }
  4928. static void
  4929. messaging_event_report_indication_cb (QmiClientNas *client,
  4930. QmiIndicationWmsEventReportOutput *output,
  4931. MMBroadbandModemQmi *self)
  4932. {
  4933. QmiWmsStorageType storage;
  4934. guint32 memory_index;
  4935. /* Currently ignoring transfer-route MT messages */
  4936. if (qmi_indication_wms_event_report_output_get_mt_message (
  4937. output,
  4938. &storage,
  4939. &memory_index,
  4940. NULL)) {
  4941. IndicationRawReadContext *ctx;
  4942. QmiMessageWmsRawReadInput *input;
  4943. ctx = g_slice_new (IndicationRawReadContext);
  4944. ctx->self = g_object_ref (self);
  4945. ctx->client = g_object_ref (client);
  4946. ctx->storage = storage;
  4947. ctx->memory_index = memory_index;
  4948. input = qmi_message_wms_raw_read_input_new ();
  4949. qmi_message_wms_raw_read_input_set_message_memory_storage_id (
  4950. input,
  4951. storage,
  4952. memory_index,
  4953. NULL);
  4954. qmi_client_wms_raw_read (QMI_CLIENT_WMS (client),
  4955. input,
  4956. 3,
  4957. NULL,
  4958. (GAsyncReadyCallback)wms_indication_raw_read_ready,
  4959. ctx);
  4960. qmi_message_wms_raw_read_input_unref (input);
  4961. }
  4962. }
  4963. static gboolean
  4964. messaging_setup_cleanup_unsolicited_events_finish (MMIfaceModemMessaging *self,
  4965. GAsyncResult *res,
  4966. GError **error)
  4967. {
  4968. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  4969. }
  4970. static void
  4971. common_setup_cleanup_messaging_unsolicited_events (MMBroadbandModemQmi *self,
  4972. gboolean enable,
  4973. GAsyncReadyCallback callback,
  4974. gpointer user_data)
  4975. {
  4976. GSimpleAsyncResult *result;
  4977. QmiClient *client = NULL;
  4978. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  4979. QMI_SERVICE_WMS, &client,
  4980. callback, user_data))
  4981. return;
  4982. result = g_simple_async_result_new (G_OBJECT (self),
  4983. callback,
  4984. user_data,
  4985. common_setup_cleanup_messaging_unsolicited_events);
  4986. if (enable == self->priv->messaging_unsolicited_events_setup) {
  4987. mm_dbg ("Messaging unsolicited events already %s; skipping",
  4988. enable ? "setup" : "cleanup");
  4989. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  4990. g_simple_async_result_complete_in_idle (result);
  4991. g_object_unref (result);
  4992. return;
  4993. }
  4994. /* Store new state */
  4995. self->priv->messaging_unsolicited_events_setup = enable;
  4996. /* Connect/Disconnect "Event Report" indications */
  4997. if (enable) {
  4998. g_assert (self->priv->messaging_event_report_indication_id == 0);
  4999. self->priv->messaging_event_report_indication_id =
  5000. g_signal_connect (client,
  5001. "event-report",
  5002. G_CALLBACK (messaging_event_report_indication_cb),
  5003. self);
  5004. } else {
  5005. g_assert (self->priv->messaging_event_report_indication_id != 0);
  5006. g_signal_handler_disconnect (client, self->priv->messaging_event_report_indication_id);
  5007. self->priv->messaging_event_report_indication_id = 0;
  5008. }
  5009. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  5010. g_simple_async_result_complete_in_idle (result);
  5011. g_object_unref (result);
  5012. }
  5013. static void
  5014. messaging_cleanup_unsolicited_events (MMIfaceModemMessaging *self,
  5015. GAsyncReadyCallback callback,
  5016. gpointer user_data)
  5017. {
  5018. common_setup_cleanup_messaging_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  5019. FALSE,
  5020. callback,
  5021. user_data);
  5022. }
  5023. static void
  5024. messaging_setup_unsolicited_events (MMIfaceModemMessaging *self,
  5025. GAsyncReadyCallback callback,
  5026. gpointer user_data)
  5027. {
  5028. common_setup_cleanup_messaging_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  5029. TRUE,
  5030. callback,
  5031. user_data);
  5032. }
  5033. /*****************************************************************************/
  5034. /* Enable/Disable unsolicited events (Messaging interface) */
  5035. typedef struct {
  5036. MMBroadbandModemQmi *self;
  5037. GSimpleAsyncResult *result;
  5038. QmiClientWms *client;
  5039. gboolean enable;
  5040. } EnableMessagingUnsolicitedEventsContext;
  5041. static void
  5042. enable_messaging_unsolicited_events_context_complete_and_free (EnableMessagingUnsolicitedEventsContext *ctx)
  5043. {
  5044. g_simple_async_result_complete (ctx->result);
  5045. g_object_unref (ctx->result);
  5046. g_object_unref (ctx->client);
  5047. g_object_unref (ctx->self);
  5048. g_free (ctx);
  5049. }
  5050. static gboolean
  5051. messaging_enable_disable_unsolicited_events_finish (MMIfaceModemMessaging *self,
  5052. GAsyncResult *res,
  5053. GError **error)
  5054. {
  5055. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  5056. }
  5057. static void
  5058. ser_messaging_indicator_ready (QmiClientWms *client,
  5059. GAsyncResult *res,
  5060. EnableMessagingUnsolicitedEventsContext *ctx)
  5061. {
  5062. QmiMessageWmsSetEventReportOutput *output = NULL;
  5063. GError *error = NULL;
  5064. output = qmi_client_wms_set_event_report_finish (client, res, &error);
  5065. if (!output) {
  5066. mm_dbg ("QMI operation failed: '%s'", error->message);
  5067. g_error_free (error);
  5068. } else if (!qmi_message_wms_set_event_report_output_get_result (output, &error)) {
  5069. mm_dbg ("Couldn't set event report: '%s'", error->message);
  5070. g_error_free (error);
  5071. }
  5072. if (output)
  5073. qmi_message_wms_set_event_report_output_unref (output);
  5074. /* Just ignore errors for now */
  5075. ctx->self->priv->messaging_unsolicited_events_enabled = ctx->enable;
  5076. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5077. enable_messaging_unsolicited_events_context_complete_and_free (ctx);
  5078. }
  5079. static void
  5080. common_enable_disable_messaging_unsolicited_events (MMBroadbandModemQmi *self,
  5081. gboolean enable,
  5082. GAsyncReadyCallback callback,
  5083. gpointer user_data)
  5084. {
  5085. EnableMessagingUnsolicitedEventsContext *ctx;
  5086. GSimpleAsyncResult *result;
  5087. QmiClient *client = NULL;
  5088. QmiMessageWmsSetEventReportInput *input;
  5089. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  5090. QMI_SERVICE_WMS, &client,
  5091. callback, user_data))
  5092. return;
  5093. result = g_simple_async_result_new (G_OBJECT (self),
  5094. callback,
  5095. user_data,
  5096. common_enable_disable_messaging_unsolicited_events);
  5097. if (enable == self->priv->messaging_unsolicited_events_enabled) {
  5098. mm_dbg ("Messaging unsolicited events already %s; skipping",
  5099. enable ? "enabled" : "disabled");
  5100. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  5101. g_simple_async_result_complete_in_idle (result);
  5102. g_object_unref (result);
  5103. return;
  5104. }
  5105. ctx = g_new0 (EnableMessagingUnsolicitedEventsContext, 1);
  5106. ctx->self = g_object_ref (self);
  5107. ctx->client = g_object_ref (client);
  5108. ctx->enable = enable;
  5109. ctx->result = result;
  5110. input = qmi_message_wms_set_event_report_input_new ();
  5111. qmi_message_wms_set_event_report_input_set_new_mt_message_indicator (
  5112. input,
  5113. ctx->enable,
  5114. NULL);
  5115. qmi_client_wms_set_event_report (
  5116. ctx->client,
  5117. input,
  5118. 5,
  5119. NULL,
  5120. (GAsyncReadyCallback)ser_messaging_indicator_ready,
  5121. ctx);
  5122. qmi_message_wms_set_event_report_input_unref (input);
  5123. }
  5124. static void
  5125. messaging_disable_unsolicited_events (MMIfaceModemMessaging *self,
  5126. GAsyncReadyCallback callback,
  5127. gpointer user_data)
  5128. {
  5129. common_enable_disable_messaging_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  5130. FALSE,
  5131. callback,
  5132. user_data);
  5133. }
  5134. static void
  5135. messaging_enable_unsolicited_events (MMIfaceModemMessaging *self,
  5136. GAsyncReadyCallback callback,
  5137. gpointer user_data)
  5138. {
  5139. common_enable_disable_messaging_unsolicited_events (MM_BROADBAND_MODEM_QMI (self),
  5140. TRUE,
  5141. callback,
  5142. user_data);
  5143. }
  5144. /*****************************************************************************/
  5145. /* Create SMS (Messaging interface) */
  5146. static MMSms *
  5147. messaging_create_sms (MMIfaceModemMessaging *self)
  5148. {
  5149. return mm_sms_qmi_new (MM_BASE_MODEM (self));
  5150. }
  5151. /*****************************************************************************/
  5152. /* Location capabilities loading (Location interface) */
  5153. static MMModemLocationSource
  5154. location_load_capabilities_finish (MMIfaceModemLocation *self,
  5155. GAsyncResult *res,
  5156. GError **error)
  5157. {
  5158. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  5159. return MM_MODEM_LOCATION_SOURCE_NONE;
  5160. return (MMModemLocationSource) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
  5161. G_SIMPLE_ASYNC_RESULT (res)));
  5162. }
  5163. static void
  5164. parent_load_capabilities_ready (MMIfaceModemLocation *self,
  5165. GAsyncResult *res,
  5166. GSimpleAsyncResult *simple)
  5167. {
  5168. MMModemLocationSource sources;
  5169. GError *error = NULL;
  5170. MMQmiPort *port;
  5171. sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
  5172. if (error) {
  5173. g_simple_async_result_take_error (simple, error);
  5174. g_simple_async_result_complete (simple);
  5175. g_object_unref (simple);
  5176. return;
  5177. }
  5178. port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
  5179. /* Now our own checks */
  5180. /* If we have support for the PDS client, GPS location is supported */
  5181. if (port && mm_qmi_port_peek_client (port,
  5182. QMI_SERVICE_PDS,
  5183. MM_QMI_PORT_FLAG_DEFAULT))
  5184. sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW);
  5185. /* If the modem is CDMA, we have support for CDMA BS location */
  5186. if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (self)))
  5187. sources |= MM_MODEM_LOCATION_SOURCE_CDMA_BS;
  5188. /* So we're done, complete */
  5189. g_simple_async_result_set_op_res_gpointer (simple,
  5190. GUINT_TO_POINTER (sources),
  5191. NULL);
  5192. g_simple_async_result_complete (simple);
  5193. g_object_unref (simple);
  5194. }
  5195. static void
  5196. location_load_capabilities (MMIfaceModemLocation *self,
  5197. GAsyncReadyCallback callback,
  5198. gpointer user_data)
  5199. {
  5200. GSimpleAsyncResult *result;
  5201. result = g_simple_async_result_new (G_OBJECT (self),
  5202. callback,
  5203. user_data,
  5204. location_load_capabilities);
  5205. /* Chain up parent's setup */
  5206. iface_modem_location_parent->load_capabilities (
  5207. self,
  5208. (GAsyncReadyCallback)parent_load_capabilities_ready,
  5209. result);
  5210. }
  5211. /*****************************************************************************/
  5212. /* Disable location gathering (Location interface) */
  5213. typedef struct {
  5214. MMBroadbandModemQmi *self;
  5215. QmiClientPds *client;
  5216. GSimpleAsyncResult *result;
  5217. } DisableLocationGatheringContext;
  5218. static void
  5219. disable_location_gathering_context_complete_and_free (DisableLocationGatheringContext *ctx)
  5220. {
  5221. g_simple_async_result_complete_in_idle (ctx->result);
  5222. g_object_unref (ctx->result);
  5223. if (ctx->client)
  5224. g_object_unref (ctx->client);
  5225. g_object_unref (ctx->self);
  5226. g_slice_free (DisableLocationGatheringContext, ctx);
  5227. }
  5228. static gboolean
  5229. disable_location_gathering_finish (MMIfaceModemLocation *self,
  5230. GAsyncResult *res,
  5231. GError **error)
  5232. {
  5233. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  5234. }
  5235. static void
  5236. gps_service_state_stop_ready (QmiClientPds *client,
  5237. GAsyncResult *res,
  5238. DisableLocationGatheringContext *ctx)
  5239. {
  5240. QmiMessagePdsSetGpsServiceStateOutput *output = NULL;
  5241. GError *error = NULL;
  5242. output = qmi_client_pds_set_gps_service_state_finish (client, res, &error);
  5243. if (!output) {
  5244. g_prefix_error (&error, "QMI operation failed: ");
  5245. g_simple_async_result_take_error (ctx->result, error);
  5246. disable_location_gathering_context_complete_and_free (ctx);
  5247. return;
  5248. }
  5249. if (!qmi_message_pds_set_gps_service_state_output_get_result (output, &error)) {
  5250. if (!g_error_matches (error,
  5251. QMI_PROTOCOL_ERROR,
  5252. QMI_PROTOCOL_ERROR_NO_EFFECT)) {
  5253. g_prefix_error (&error, "Couldn't set GPS service state: ");
  5254. g_simple_async_result_take_error (ctx->result, error);
  5255. disable_location_gathering_context_complete_and_free (ctx);
  5256. qmi_message_pds_set_gps_service_state_output_unref (output);
  5257. return;
  5258. }
  5259. g_error_free (error);
  5260. }
  5261. qmi_message_pds_set_gps_service_state_output_unref (output);
  5262. mm_dbg ("Removing location event report indication handling");
  5263. g_assert (ctx->self->priv->location_event_report_indication_id != 0);
  5264. g_signal_handler_disconnect (client, ctx->self->priv->location_event_report_indication_id);
  5265. ctx->self->priv->location_event_report_indication_id = 0;
  5266. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5267. disable_location_gathering_context_complete_and_free (ctx);
  5268. }
  5269. static void
  5270. disable_location_gathering (MMIfaceModemLocation *self,
  5271. MMModemLocationSource source,
  5272. GAsyncReadyCallback callback,
  5273. gpointer user_data)
  5274. {
  5275. DisableLocationGatheringContext *ctx;
  5276. QmiClient *client = NULL;
  5277. gboolean stop_gps = FALSE;
  5278. GSimpleAsyncResult *result;
  5279. result = g_simple_async_result_new (G_OBJECT (self),
  5280. callback,
  5281. user_data,
  5282. disable_location_gathering);
  5283. /* Nothing to be done to disable 3GPP or CDMA locations */
  5284. if (source == MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI ||
  5285. source == MM_MODEM_LOCATION_SOURCE_CDMA_BS) {
  5286. g_simple_async_result_set_op_res_gboolean (result, TRUE);
  5287. g_simple_async_result_complete_in_idle (result);
  5288. g_object_unref (result);
  5289. return;
  5290. }
  5291. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  5292. QMI_SERVICE_PDS, &client,
  5293. callback, user_data)) {
  5294. g_object_unref (result);
  5295. return;
  5296. }
  5297. ctx = g_slice_new0 (DisableLocationGatheringContext);
  5298. ctx->self = g_object_ref (self);
  5299. ctx->client = g_object_ref (client);
  5300. ctx->result = result;
  5301. /* Only stop GPS engine if no GPS-related sources enabled */
  5302. if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
  5303. MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
  5304. ctx->self->priv->enabled_sources &= ~source;
  5305. if (!(ctx->self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
  5306. MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
  5307. stop_gps = TRUE;
  5308. }
  5309. if (stop_gps) {
  5310. QmiMessagePdsSetGpsServiceStateInput *input;
  5311. input = qmi_message_pds_set_gps_service_state_input_new ();
  5312. qmi_message_pds_set_gps_service_state_input_set_state (input, FALSE, NULL);
  5313. qmi_client_pds_set_gps_service_state (
  5314. ctx->client,
  5315. input,
  5316. 10,
  5317. NULL, /* cancellable */
  5318. (GAsyncReadyCallback)gps_service_state_stop_ready,
  5319. ctx);
  5320. qmi_message_pds_set_gps_service_state_input_unref (input);
  5321. return;
  5322. }
  5323. /* If still some GPS needed, just return */
  5324. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5325. disable_location_gathering_context_complete_and_free (ctx);
  5326. }
  5327. /*****************************************************************************/
  5328. /* Enable location gathering (Location interface) */
  5329. static void
  5330. location_event_report_indication_cb (QmiClientPds *client,
  5331. QmiIndicationPdsEventReportOutput *output,
  5332. MMBroadbandModemQmi *self)
  5333. {
  5334. QmiPdsPositionSessionStatus session_status;
  5335. const gchar *nmea;
  5336. if (qmi_indication_pds_event_report_output_get_position_session_status (
  5337. output,
  5338. &session_status,
  5339. NULL)) {
  5340. mm_dbg ("[GPS] session status changed: '%s'",
  5341. qmi_pds_position_session_status_get_string (session_status));
  5342. }
  5343. if (qmi_indication_pds_event_report_output_get_nmea_position (
  5344. output,
  5345. &nmea,
  5346. NULL)) {
  5347. mm_dbg ("[NMEA] %s", nmea);
  5348. mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), nmea);
  5349. }
  5350. }
  5351. typedef struct {
  5352. MMBroadbandModemQmi *self;
  5353. QmiClientPds *client;
  5354. GSimpleAsyncResult *result;
  5355. MMModemLocationSource source;
  5356. } EnableLocationGatheringContext;
  5357. static void
  5358. enable_location_gathering_context_complete_and_free (EnableLocationGatheringContext *ctx)
  5359. {
  5360. g_simple_async_result_complete (ctx->result);
  5361. g_object_unref (ctx->result);
  5362. if (ctx->client)
  5363. g_object_unref (ctx->client);
  5364. g_object_unref (ctx->self);
  5365. g_slice_free (EnableLocationGatheringContext, ctx);
  5366. }
  5367. static gboolean
  5368. enable_location_gathering_finish (MMIfaceModemLocation *self,
  5369. GAsyncResult *res,
  5370. GError **error)
  5371. {
  5372. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  5373. }
  5374. static void
  5375. ser_location_ready (QmiClientPds *client,
  5376. GAsyncResult *res,
  5377. EnableLocationGatheringContext *ctx)
  5378. {
  5379. QmiMessagePdsSetEventReportOutput *output = NULL;
  5380. GError *error = NULL;
  5381. output = qmi_client_pds_set_event_report_finish (client, res, &error);
  5382. if (!output) {
  5383. g_prefix_error (&error, "QMI operation failed: ");
  5384. g_simple_async_result_take_error (ctx->result, error);
  5385. enable_location_gathering_context_complete_and_free (ctx);
  5386. return;
  5387. }
  5388. if (!qmi_message_pds_set_event_report_output_get_result (output, &error)) {
  5389. g_prefix_error (&error, "Couldn't set event report: ");
  5390. g_simple_async_result_take_error (ctx->result, error);
  5391. enable_location_gathering_context_complete_and_free (ctx);
  5392. qmi_message_pds_set_event_report_output_unref (output);
  5393. return;
  5394. }
  5395. qmi_message_pds_set_event_report_output_unref (output);
  5396. mm_dbg ("Adding location event report indication handling");
  5397. g_assert (ctx->self->priv->location_event_report_indication_id == 0);
  5398. ctx->self->priv->location_event_report_indication_id =
  5399. g_signal_connect (client,
  5400. "event-report",
  5401. G_CALLBACK (location_event_report_indication_cb),
  5402. ctx->self);
  5403. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5404. enable_location_gathering_context_complete_and_free (ctx);
  5405. }
  5406. static void
  5407. auto_tracking_state_start_ready (QmiClientPds *client,
  5408. GAsyncResult *res,
  5409. EnableLocationGatheringContext *ctx)
  5410. {
  5411. QmiMessagePdsSetEventReportInput *input;
  5412. QmiMessagePdsSetAutoTrackingStateOutput *output = NULL;
  5413. GError *error = NULL;
  5414. output = qmi_client_pds_set_auto_tracking_state_finish (client, res, &error);
  5415. if (!output) {
  5416. g_prefix_error (&error, "QMI operation failed: ");
  5417. g_simple_async_result_take_error (ctx->result, error);
  5418. enable_location_gathering_context_complete_and_free (ctx);
  5419. return;
  5420. }
  5421. if (!qmi_message_pds_set_auto_tracking_state_output_get_result (output, &error)) {
  5422. if (!g_error_matches (error,
  5423. QMI_PROTOCOL_ERROR,
  5424. QMI_PROTOCOL_ERROR_NO_EFFECT)) {
  5425. g_prefix_error (&error, "Couldn't set auto-tracking state: ");
  5426. g_simple_async_result_take_error (ctx->result, error);
  5427. enable_location_gathering_context_complete_and_free (ctx);
  5428. qmi_message_pds_set_auto_tracking_state_output_unref (output);
  5429. return;
  5430. }
  5431. g_error_free (error);
  5432. }
  5433. qmi_message_pds_set_auto_tracking_state_output_unref (output);
  5434. /* Only gather standard NMEA traces */
  5435. input = qmi_message_pds_set_event_report_input_new ();
  5436. qmi_message_pds_set_event_report_input_set_nmea_position_reporting (input, TRUE, NULL);
  5437. qmi_client_pds_set_event_report (
  5438. ctx->client,
  5439. input,
  5440. 5,
  5441. NULL,
  5442. (GAsyncReadyCallback)ser_location_ready,
  5443. ctx);
  5444. qmi_message_pds_set_event_report_input_unref (input);
  5445. }
  5446. static void
  5447. gps_service_state_start_ready (QmiClientPds *client,
  5448. GAsyncResult *res,
  5449. EnableLocationGatheringContext *ctx)
  5450. {
  5451. QmiMessagePdsSetAutoTrackingStateInput *input;
  5452. QmiMessagePdsSetGpsServiceStateOutput *output = NULL;
  5453. GError *error = NULL;
  5454. output = qmi_client_pds_set_gps_service_state_finish (client, res, &error);
  5455. if (!output) {
  5456. g_prefix_error (&error, "QMI operation failed: ");
  5457. g_simple_async_result_take_error (ctx->result, error);
  5458. enable_location_gathering_context_complete_and_free (ctx);
  5459. return;
  5460. }
  5461. if (!qmi_message_pds_set_gps_service_state_output_get_result (output, &error)) {
  5462. if (!g_error_matches (error,
  5463. QMI_PROTOCOL_ERROR,
  5464. QMI_PROTOCOL_ERROR_NO_EFFECT)) {
  5465. g_prefix_error (&error, "Couldn't set GPS service state: ");
  5466. g_simple_async_result_take_error (ctx->result, error);
  5467. enable_location_gathering_context_complete_and_free (ctx);
  5468. qmi_message_pds_set_gps_service_state_output_unref (output);
  5469. return;
  5470. }
  5471. g_error_free (error);
  5472. }
  5473. qmi_message_pds_set_gps_service_state_output_unref (output);
  5474. /* Enable auto-tracking for a continuous fix */
  5475. input = qmi_message_pds_set_auto_tracking_state_input_new ();
  5476. qmi_message_pds_set_auto_tracking_state_input_set_state (input, TRUE, NULL);
  5477. qmi_client_pds_set_auto_tracking_state (
  5478. ctx->client,
  5479. input,
  5480. 10,
  5481. NULL, /* cancellable */
  5482. (GAsyncReadyCallback)auto_tracking_state_start_ready,
  5483. ctx);
  5484. qmi_message_pds_set_auto_tracking_state_input_unref (input);
  5485. }
  5486. static void
  5487. parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
  5488. GAsyncResult *res,
  5489. EnableLocationGatheringContext *ctx)
  5490. {
  5491. gboolean start_gps = FALSE;
  5492. GError *error = NULL;
  5493. if (!iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) {
  5494. g_simple_async_result_take_error (ctx->result, error);
  5495. enable_location_gathering_context_complete_and_free (ctx);
  5496. return;
  5497. }
  5498. /* Now our own enabling */
  5499. /* CDMA modems need to re-run registration checks when enabling the CDMA BS
  5500. * location source, so that we get up to date BS location information.
  5501. * Note that we don't care for when the registration checks get finished.
  5502. */
  5503. if (ctx->source == MM_MODEM_LOCATION_SOURCE_CDMA_BS &&
  5504. mm_iface_modem_is_cdma (MM_IFACE_MODEM (self))) {
  5505. /* Reload registration to get LAC/CI */
  5506. mm_iface_modem_cdma_run_registration_checks (MM_IFACE_MODEM_CDMA (self), NULL, NULL);
  5507. }
  5508. /* NMEA and RAW are both enabled in the same way */
  5509. if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
  5510. MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
  5511. /* Only start GPS engine if not done already */
  5512. if (!(ctx->self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
  5513. MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
  5514. start_gps = TRUE;
  5515. ctx->self->priv->enabled_sources |= ctx->source;
  5516. }
  5517. if (start_gps) {
  5518. QmiMessagePdsSetGpsServiceStateInput *input;
  5519. QmiClient *client;
  5520. client = peek_qmi_client (ctx->self, QMI_SERVICE_PDS, &error);
  5521. if (!client) {
  5522. g_simple_async_result_take_error (ctx->result, error);
  5523. enable_location_gathering_context_complete_and_free (ctx);
  5524. return;
  5525. }
  5526. /* Keep a ref around */
  5527. ctx->client = g_object_ref (client);
  5528. input = qmi_message_pds_set_gps_service_state_input_new ();
  5529. qmi_message_pds_set_gps_service_state_input_set_state (input, TRUE, NULL);
  5530. qmi_client_pds_set_gps_service_state (
  5531. ctx->client,
  5532. input,
  5533. 10,
  5534. NULL, /* cancellable */
  5535. (GAsyncReadyCallback)gps_service_state_start_ready,
  5536. ctx);
  5537. qmi_message_pds_set_gps_service_state_input_unref (input);
  5538. return;
  5539. }
  5540. /* For any other location (e.g. 3GPP), or if GPS already running just return */
  5541. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5542. enable_location_gathering_context_complete_and_free (ctx);
  5543. }
  5544. static void
  5545. enable_location_gathering (MMIfaceModemLocation *self,
  5546. MMModemLocationSource source,
  5547. GAsyncReadyCallback callback,
  5548. gpointer user_data)
  5549. {
  5550. EnableLocationGatheringContext *ctx;
  5551. ctx = g_slice_new0 (EnableLocationGatheringContext);
  5552. ctx->self = g_object_ref (self);
  5553. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  5554. callback,
  5555. user_data,
  5556. enable_location_gathering);
  5557. ctx->source = source;
  5558. /* Chain up parent's gathering enable */
  5559. iface_modem_location_parent->enable_location_gathering (
  5560. self,
  5561. source,
  5562. (GAsyncReadyCallback)parent_enable_location_gathering_ready,
  5563. ctx);
  5564. }
  5565. /*****************************************************************************/
  5566. /* Check firmware support (Firmware interface) */
  5567. typedef struct {
  5568. gchar *build_id;
  5569. GArray *modem_unique_id;
  5570. GArray *pri_unique_id;
  5571. gboolean current;
  5572. } FirmwarePair;
  5573. static void
  5574. firmware_pair_free (FirmwarePair *pair)
  5575. {
  5576. g_free (pair->build_id);
  5577. g_array_unref (pair->modem_unique_id);
  5578. g_array_unref (pair->pri_unique_id);
  5579. g_slice_free (FirmwarePair, pair);
  5580. }
  5581. typedef struct {
  5582. MMBroadbandModemQmi *self;
  5583. QmiClientDms *client;
  5584. GSimpleAsyncResult *result;
  5585. GList *pairs;
  5586. GList *l;
  5587. } FirmwareCheckSupportContext;
  5588. static void
  5589. firmware_check_support_context_complete_and_free (FirmwareCheckSupportContext *ctx)
  5590. {
  5591. g_simple_async_result_complete (ctx->result);
  5592. g_object_unref (ctx->result);
  5593. g_list_free_full (ctx->pairs, (GDestroyNotify)firmware_pair_free);
  5594. g_object_unref (ctx->self);
  5595. g_object_unref (ctx->client);
  5596. g_slice_free (FirmwareCheckSupportContext, ctx);
  5597. }
  5598. static gboolean
  5599. firmware_check_support_finish (MMIfaceModemFirmware *self,
  5600. GAsyncResult *res,
  5601. GError **error)
  5602. {
  5603. /* Never fails, just says TRUE or FALSE */
  5604. return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res));
  5605. }
  5606. static void get_next_image_info (FirmwareCheckSupportContext *ctx);
  5607. static void
  5608. get_pri_image_info_ready (QmiClientDms *client,
  5609. GAsyncResult *res,
  5610. FirmwareCheckSupportContext *ctx)
  5611. {
  5612. QmiMessageDmsGetStoredImageInfoOutput *output;
  5613. GError *error = NULL;
  5614. FirmwarePair *current;
  5615. current = (FirmwarePair *)ctx->l->data;
  5616. output = qmi_client_dms_get_stored_image_info_finish (client, res, &error);
  5617. if (!output ||
  5618. !qmi_message_dms_get_stored_image_info_output_get_result (output, &error)) {
  5619. mm_warn ("Couldn't get detailed info for PRI image with build ID '%s': %s",
  5620. current->build_id,
  5621. error->message);
  5622. g_error_free (error);
  5623. } else {
  5624. gchar *unique_id_str;
  5625. MMFirmwareProperties *firmware;
  5626. firmware = mm_firmware_properties_new (MM_FIRMWARE_IMAGE_TYPE_GOBI,
  5627. current->build_id);
  5628. unique_id_str = mm_utils_bin2hexstr ((const guint8 *)current->pri_unique_id->data,
  5629. current->pri_unique_id->len);
  5630. mm_firmware_properties_set_gobi_pri_unique_id (firmware, unique_id_str);
  5631. g_free (unique_id_str);
  5632. unique_id_str = mm_utils_bin2hexstr ((const guint8 *)current->modem_unique_id->data,
  5633. current->modem_unique_id->len);
  5634. mm_firmware_properties_set_gobi_modem_unique_id (firmware, unique_id_str);
  5635. g_free (unique_id_str);
  5636. /* Boot version (optional) */
  5637. {
  5638. guint16 boot_major_version;
  5639. guint16 boot_minor_version;
  5640. if (qmi_message_dms_get_stored_image_info_output_get_boot_version (
  5641. output,
  5642. &boot_major_version,
  5643. &boot_minor_version,
  5644. NULL)) {
  5645. gchar *aux;
  5646. aux = g_strdup_printf ("%u.%u", boot_major_version, boot_minor_version);
  5647. mm_firmware_properties_set_gobi_boot_version (firmware, aux);
  5648. g_free (aux);
  5649. }
  5650. }
  5651. /* PRI version (optional) */
  5652. {
  5653. guint32 pri_version;
  5654. const gchar *pri_info;
  5655. if (qmi_message_dms_get_stored_image_info_output_get_pri_version (
  5656. output,
  5657. &pri_version,
  5658. &pri_info,
  5659. NULL)) {
  5660. gchar *aux;
  5661. aux = g_strdup_printf ("%u", pri_version);
  5662. mm_firmware_properties_set_gobi_pri_version (firmware, aux);
  5663. g_free (aux);
  5664. mm_firmware_properties_set_gobi_pri_info (firmware, pri_info);
  5665. }
  5666. }
  5667. /* Add firmware image to our internal list */
  5668. ctx->self->priv->firmware_list = g_list_append (ctx->self->priv->firmware_list,
  5669. firmware);
  5670. /* If this is is also the current image running, keep it */
  5671. if (current->current) {
  5672. if (ctx->self->priv->current_firmware)
  5673. mm_warn ("A current firmware is already set (%s), not setting '%s' as current",
  5674. mm_firmware_properties_get_unique_id (ctx->self->priv->current_firmware),
  5675. current->build_id);
  5676. else
  5677. ctx->self->priv->current_firmware = g_object_ref (firmware);
  5678. }
  5679. qmi_message_dms_get_stored_image_info_output_unref (output);
  5680. }
  5681. /* Go on to the next one */
  5682. ctx->l = g_list_next (ctx->l);
  5683. get_next_image_info (ctx);
  5684. }
  5685. static void
  5686. get_next_image_info (FirmwareCheckSupportContext *ctx)
  5687. {
  5688. QmiMessageDmsGetStoredImageInfoInputImage image_id;
  5689. QmiMessageDmsGetStoredImageInfoInput *input;
  5690. FirmwarePair *current;
  5691. if (!ctx->l) {
  5692. /* We're done */
  5693. if (!ctx->self->priv->firmware_list) {
  5694. mm_warn ("No valid firmware images listed. "
  5695. "Assuming firmware unsupported.");
  5696. g_simple_async_result_set_op_res_gboolean (ctx->result, FALSE);
  5697. } else
  5698. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5699. firmware_check_support_context_complete_and_free (ctx);
  5700. return;
  5701. }
  5702. current = (FirmwarePair *)ctx->l->data;
  5703. /* Query PRI image info */
  5704. image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI;
  5705. image_id.unique_id = current->pri_unique_id;
  5706. image_id.build_id = current->build_id;
  5707. input = qmi_message_dms_get_stored_image_info_input_new ();
  5708. qmi_message_dms_get_stored_image_info_input_set_image (input, &image_id, NULL);
  5709. qmi_client_dms_get_stored_image_info (ctx->client,
  5710. input,
  5711. 10,
  5712. NULL,
  5713. (GAsyncReadyCallback)get_pri_image_info_ready,
  5714. ctx);
  5715. qmi_message_dms_get_stored_image_info_input_unref (input);
  5716. }
  5717. static void
  5718. list_stored_images_ready (QmiClientDms *client,
  5719. GAsyncResult *res,
  5720. FirmwareCheckSupportContext *ctx)
  5721. {
  5722. GArray *array;
  5723. gint pri_id;
  5724. gint modem_id;
  5725. guint i;
  5726. guint j;
  5727. QmiMessageDmsListStoredImagesOutputListImage *image_pri;
  5728. QmiMessageDmsListStoredImagesOutputListImage *image_modem;
  5729. QmiMessageDmsListStoredImagesOutput *output;
  5730. output = qmi_client_dms_list_stored_images_finish (client, res, NULL);
  5731. if (!output ||
  5732. !qmi_message_dms_list_stored_images_output_get_result (output, NULL)) {
  5733. /* Assume firmware unsupported */
  5734. g_simple_async_result_set_op_res_gboolean (ctx->result, FALSE);
  5735. firmware_check_support_context_complete_and_free (ctx);
  5736. if (output)
  5737. qmi_message_dms_list_stored_images_output_unref (output);
  5738. return;
  5739. }
  5740. qmi_message_dms_list_stored_images_output_get_list (
  5741. output,
  5742. &array,
  5743. NULL);
  5744. /* Find which index corresponds to each image type */
  5745. pri_id = -1;
  5746. modem_id = -1;
  5747. for (i = 0; i < array->len; i++) {
  5748. QmiMessageDmsListStoredImagesOutputListImage *image;
  5749. image = &g_array_index (array,
  5750. QmiMessageDmsListStoredImagesOutputListImage,
  5751. i);
  5752. switch (image->type) {
  5753. case QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI:
  5754. if (pri_id != -1)
  5755. mm_warn ("Multiple array elements found with PRI type");
  5756. else
  5757. pri_id = (gint)i;
  5758. break;
  5759. case QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM:
  5760. if (modem_id != -1)
  5761. mm_warn ("Multiple array elements found with MODEM type");
  5762. else
  5763. modem_id = (gint)i;
  5764. break;
  5765. default:
  5766. break;
  5767. }
  5768. }
  5769. if (pri_id < 0 || modem_id < 0) {
  5770. mm_warn ("We need both PRI (%s) and MODEM (%s) images. "
  5771. "Assuming firmware unsupported.",
  5772. pri_id < 0 ? "not found" : "found",
  5773. modem_id < 0 ? "not found" : "found");
  5774. g_simple_async_result_set_op_res_gboolean (ctx->result, FALSE);
  5775. firmware_check_support_context_complete_and_free (ctx);
  5776. qmi_message_dms_list_stored_images_output_unref (output);
  5777. return;
  5778. }
  5779. /* Loop PRI images and try to find a pairing MODEM image with same boot ID */
  5780. image_pri = &g_array_index (array,
  5781. QmiMessageDmsListStoredImagesOutputListImage,
  5782. pri_id);
  5783. image_modem = &g_array_index (array,
  5784. QmiMessageDmsListStoredImagesOutputListImage,
  5785. modem_id);
  5786. for (i = 0; i < image_pri->sublist->len; i++) {
  5787. QmiMessageDmsListStoredImagesOutputListImageSublistSublistElement *subimage_pri;
  5788. subimage_pri = &g_array_index (image_pri->sublist,
  5789. QmiMessageDmsListStoredImagesOutputListImageSublistSublistElement,
  5790. i);
  5791. for (j = 0; j < image_modem->sublist->len; j++) {
  5792. QmiMessageDmsListStoredImagesOutputListImageSublistSublistElement *subimage_modem;
  5793. subimage_modem = &g_array_index (image_modem->sublist,
  5794. QmiMessageDmsListStoredImagesOutputListImageSublistSublistElement,
  5795. j);
  5796. if (g_str_equal (subimage_pri->build_id, subimage_modem->build_id)) {
  5797. FirmwarePair *pair;
  5798. mm_dbg ("Found pairing PRI+MODEM images with build ID '%s'", subimage_pri->build_id);
  5799. pair = g_slice_new (FirmwarePair);
  5800. pair->build_id = g_strdup (subimage_pri->build_id);
  5801. pair->modem_unique_id = g_array_ref (subimage_modem->unique_id);
  5802. pair->pri_unique_id = g_array_ref (subimage_pri->unique_id);
  5803. pair->current = (image_pri->index_of_running_image == i ? TRUE : FALSE);
  5804. ctx->pairs = g_list_append (ctx->pairs, pair);
  5805. break;
  5806. }
  5807. }
  5808. if (j == image_modem->sublist->len)
  5809. mm_dbg ("Pairing for PRI image with build ID '%s' not found", subimage_pri->build_id);
  5810. }
  5811. if (!ctx->pairs) {
  5812. mm_warn ("No valid PRI+MODEM pairs found. "
  5813. "Assuming firmware unsupported.");
  5814. g_simple_async_result_set_op_res_gboolean (ctx->result, FALSE);
  5815. firmware_check_support_context_complete_and_free (ctx);
  5816. qmi_message_dms_list_stored_images_output_unref (output);
  5817. return;
  5818. }
  5819. /* Firmware is supported; now keep on loading info for each image and cache it */
  5820. qmi_message_dms_list_stored_images_output_unref (output);
  5821. ctx->l = ctx->pairs;
  5822. get_next_image_info (ctx);
  5823. }
  5824. static void
  5825. firmware_check_support (MMIfaceModemFirmware *self,
  5826. GAsyncReadyCallback callback,
  5827. gpointer user_data)
  5828. {
  5829. FirmwareCheckSupportContext *ctx;
  5830. QmiClient *client = NULL;
  5831. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  5832. QMI_SERVICE_DMS, &client,
  5833. callback, user_data))
  5834. return;
  5835. ctx = g_slice_new0 (FirmwareCheckSupportContext);
  5836. ctx->self = g_object_ref (self);
  5837. ctx->client = g_object_ref (client);
  5838. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  5839. callback,
  5840. user_data,
  5841. firmware_check_support);
  5842. mm_dbg ("loading firmware images...");
  5843. qmi_client_dms_list_stored_images (QMI_CLIENT_DMS (client),
  5844. NULL,
  5845. 10,
  5846. NULL,
  5847. (GAsyncReadyCallback)list_stored_images_ready,
  5848. ctx);
  5849. }
  5850. /*****************************************************************************/
  5851. /* Load firmware list (Firmware interface) */
  5852. static GList *
  5853. firmware_load_list_finish (MMIfaceModemFirmware *self,
  5854. GAsyncResult *res,
  5855. GError **error)
  5856. {
  5857. return (GList *)g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
  5858. }
  5859. static void
  5860. firmware_load_list (MMIfaceModemFirmware *_self,
  5861. GAsyncReadyCallback callback,
  5862. gpointer user_data)
  5863. {
  5864. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  5865. GSimpleAsyncResult *result;
  5866. GList *dup;
  5867. result = g_simple_async_result_new (G_OBJECT (self),
  5868. callback,
  5869. user_data,
  5870. firmware_load_list);
  5871. /* We'll return the new list of new references we create here */
  5872. dup = g_list_copy (self->priv->firmware_list);
  5873. g_list_foreach (dup, (GFunc)g_object_ref, NULL);
  5874. g_simple_async_result_set_op_res_gpointer (result, dup, NULL);
  5875. g_simple_async_result_complete_in_idle (result);
  5876. g_object_unref (result);
  5877. }
  5878. /*****************************************************************************/
  5879. /* Load current firmware (Firmware interface) */
  5880. static MMFirmwareProperties *
  5881. firmware_load_current_finish (MMIfaceModemFirmware *self,
  5882. GAsyncResult *res,
  5883. GError **error)
  5884. {
  5885. return (MMFirmwareProperties *)g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
  5886. }
  5887. static void
  5888. firmware_load_current (MMIfaceModemFirmware *_self,
  5889. GAsyncReadyCallback callback,
  5890. gpointer user_data)
  5891. {
  5892. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
  5893. GSimpleAsyncResult *result;
  5894. result = g_simple_async_result_new (G_OBJECT (self),
  5895. callback,
  5896. user_data,
  5897. firmware_load_current);
  5898. /* We'll return the reference we create here */
  5899. g_simple_async_result_set_op_res_gpointer (
  5900. result,
  5901. self->priv->current_firmware ? g_object_ref (self->priv->current_firmware) : NULL,
  5902. NULL);
  5903. g_simple_async_result_complete_in_idle (result);
  5904. g_object_unref (result);
  5905. }
  5906. /*****************************************************************************/
  5907. /* Change current firmware (Firmware interface) */
  5908. typedef struct {
  5909. MMBroadbandModemQmi *self;
  5910. QmiClientDms *client;
  5911. GSimpleAsyncResult *result;
  5912. MMFirmwareProperties *firmware;
  5913. } FirmwareChangeCurrentContext;
  5914. static void
  5915. firmware_change_current_context_complete_and_free (FirmwareChangeCurrentContext *ctx)
  5916. {
  5917. g_simple_async_result_complete_in_idle (ctx->result);
  5918. g_object_unref (ctx->result);
  5919. g_object_unref (ctx->self);
  5920. g_object_unref (ctx->client);
  5921. if (ctx->firmware)
  5922. g_object_unref (ctx->firmware);
  5923. g_slice_free (FirmwareChangeCurrentContext, ctx);
  5924. }
  5925. static gboolean
  5926. firmware_change_current_finish (MMIfaceModemFirmware *self,
  5927. GAsyncResult *res,
  5928. GError **error)
  5929. {
  5930. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  5931. }
  5932. static void
  5933. firmware_set_operating_mode_reset_ready (QmiClientDms *client,
  5934. GAsyncResult *res,
  5935. FirmwareChangeCurrentContext *ctx)
  5936. {
  5937. QmiMessageDmsSetOperatingModeOutput *output;
  5938. GError *error = NULL;
  5939. output = qmi_client_dms_set_operating_mode_finish (client, res, &error);
  5940. if (!output ||
  5941. !qmi_message_dms_set_operating_mode_output_get_result (output, &error)) {
  5942. g_simple_async_result_take_error (ctx->result, error);
  5943. } else {
  5944. mm_info ("Modem is being rebooted now");
  5945. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  5946. }
  5947. if (output)
  5948. qmi_message_dms_set_operating_mode_output_unref (output);
  5949. firmware_change_current_context_complete_and_free (ctx);
  5950. }
  5951. static void
  5952. firmware_set_operating_mode_offline_ready (QmiClientDms *client,
  5953. GAsyncResult *res,
  5954. FirmwareChangeCurrentContext *ctx)
  5955. {
  5956. QmiMessageDmsSetOperatingModeInput *input;
  5957. QmiMessageDmsSetOperatingModeOutput *output;
  5958. GError *error = NULL;
  5959. output = qmi_client_dms_set_operating_mode_finish (client, res, &error);
  5960. if (!output) {
  5961. g_simple_async_result_take_error (ctx->result, error);
  5962. firmware_change_current_context_complete_and_free (ctx);
  5963. return;
  5964. }
  5965. if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) {
  5966. g_simple_async_result_take_error (ctx->result, error);
  5967. firmware_change_current_context_complete_and_free (ctx);
  5968. qmi_message_dms_set_operating_mode_output_unref (output);
  5969. return;
  5970. }
  5971. qmi_message_dms_set_operating_mode_output_unref (output);
  5972. /* Now, go into reset mode. This will fully reboot the modem, and the current
  5973. * modem object should get disposed. */
  5974. input = qmi_message_dms_set_operating_mode_input_new ();
  5975. qmi_message_dms_set_operating_mode_input_set_mode (input, QMI_DMS_OPERATING_MODE_RESET, NULL);
  5976. qmi_client_dms_set_operating_mode (ctx->client,
  5977. input,
  5978. 20,
  5979. NULL,
  5980. (GAsyncReadyCallback)firmware_set_operating_mode_reset_ready,
  5981. ctx);
  5982. qmi_message_dms_set_operating_mode_input_unref (input);
  5983. }
  5984. static void
  5985. firmware_select_stored_image_ready (QmiClientDms *client,
  5986. GAsyncResult *res,
  5987. FirmwareChangeCurrentContext *ctx)
  5988. {
  5989. QmiMessageDmsSetOperatingModeInput *input;
  5990. QmiMessageDmsSetFirmwarePreferenceOutput *output;
  5991. GError *error = NULL;
  5992. output = qmi_client_dms_set_firmware_preference_finish (client, res, &error);
  5993. if (!output) {
  5994. g_simple_async_result_take_error (ctx->result, error);
  5995. firmware_change_current_context_complete_and_free (ctx);
  5996. return;
  5997. }
  5998. if (!qmi_message_dms_set_firmware_preference_output_get_result (output, &error)) {
  5999. g_simple_async_result_take_error (ctx->result, error);
  6000. firmware_change_current_context_complete_and_free (ctx);
  6001. qmi_message_dms_set_firmware_preference_output_unref (output);
  6002. return;
  6003. }
  6004. qmi_message_dms_set_firmware_preference_output_unref (output);
  6005. /* Now, go into offline mode */
  6006. input = qmi_message_dms_set_operating_mode_input_new ();
  6007. qmi_message_dms_set_operating_mode_input_set_mode (input, QMI_DMS_OPERATING_MODE_OFFLINE, NULL);
  6008. qmi_client_dms_set_operating_mode (ctx->client,
  6009. input,
  6010. 20,
  6011. NULL,
  6012. (GAsyncReadyCallback)firmware_set_operating_mode_offline_ready,
  6013. ctx);
  6014. qmi_message_dms_set_operating_mode_input_unref (input);
  6015. }
  6016. static MMFirmwareProperties *
  6017. find_firmware_properties_by_unique_id (MMBroadbandModemQmi *self,
  6018. const gchar *unique_id)
  6019. {
  6020. GList *l;
  6021. for (l = self->priv->firmware_list; l; l = g_list_next (l)) {
  6022. if (g_str_equal (mm_firmware_properties_get_unique_id (MM_FIRMWARE_PROPERTIES (l->data)),
  6023. unique_id))
  6024. return g_object_ref (l->data);
  6025. }
  6026. return NULL;
  6027. }
  6028. static MMFirmwareProperties *
  6029. find_firmware_properties_by_gobi_pri_info_substring (MMBroadbandModemQmi *self,
  6030. const gchar *str,
  6031. guint *n_found)
  6032. {
  6033. MMFirmwareProperties *first = NULL;
  6034. GList *l;
  6035. *n_found = 0;
  6036. for (l = self->priv->firmware_list; l; l = g_list_next (l)) {
  6037. const gchar *pri_info;
  6038. pri_info = mm_firmware_properties_get_gobi_pri_info (MM_FIRMWARE_PROPERTIES (l->data));
  6039. if (pri_info && strstr (pri_info, str)) {
  6040. if (!first && *n_found == 0)
  6041. first = g_object_ref (l->data);
  6042. else
  6043. g_clear_object (&first);
  6044. (*n_found)++;
  6045. }
  6046. }
  6047. return first;
  6048. }
  6049. static void
  6050. firmware_change_current (MMIfaceModemFirmware *self,
  6051. const gchar *unique_id,
  6052. GAsyncReadyCallback callback,
  6053. gpointer user_data)
  6054. {
  6055. QmiMessageDmsSetFirmwarePreferenceInput *input;
  6056. FirmwareChangeCurrentContext *ctx;
  6057. QmiClient *client = NULL;
  6058. GArray *array;
  6059. QmiMessageDmsSetFirmwarePreferenceInputListImage modem_image_id;
  6060. QmiMessageDmsSetFirmwarePreferenceInputListImage pri_image_id;
  6061. guint8 *tmp;
  6062. gsize tmp_len;
  6063. if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
  6064. QMI_SERVICE_DMS, &client,
  6065. callback, user_data))
  6066. return;
  6067. ctx = g_slice_new0 (FirmwareChangeCurrentContext);
  6068. ctx->self = g_object_ref (self);
  6069. ctx->client = g_object_ref (client);
  6070. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  6071. callback,
  6072. user_data,
  6073. firmware_change_current);
  6074. /* Look for the firmware image with the requested unique ID */
  6075. ctx->firmware = find_firmware_properties_by_unique_id (ctx->self, unique_id);
  6076. if (!ctx->firmware) {
  6077. guint n = 0;
  6078. /* Ok, let's look at the PRI info */
  6079. ctx->firmware = find_firmware_properties_by_gobi_pri_info_substring (ctx->self, unique_id, &n);
  6080. if (n > 1) {
  6081. g_simple_async_result_set_error (ctx->result,
  6082. MM_CORE_ERROR,
  6083. MM_CORE_ERROR_NOT_FOUND,
  6084. "Multiple firmware images (%u) found matching '%s' as PRI info substring",
  6085. n, unique_id);
  6086. firmware_change_current_context_complete_and_free (ctx);
  6087. return;
  6088. }
  6089. if (n == 0) {
  6090. g_simple_async_result_set_error (ctx->result,
  6091. MM_CORE_ERROR,
  6092. MM_CORE_ERROR_NOT_FOUND,
  6093. "Firmware with unique ID '%s' wasn't found",
  6094. unique_id);
  6095. firmware_change_current_context_complete_and_free (ctx);
  6096. return;
  6097. }
  6098. g_assert (n == 1 && MM_IS_FIRMWARE_PROPERTIES (ctx->firmware));
  6099. }
  6100. /* If we're already in the requested firmware, we're done */
  6101. if (ctx->self->priv->current_firmware &&
  6102. g_str_equal (mm_firmware_properties_get_unique_id (ctx->self->priv->current_firmware),
  6103. mm_firmware_properties_get_unique_id (ctx->firmware))) {
  6104. mm_dbg ("Modem is already running firmware image '%s'",
  6105. mm_firmware_properties_get_unique_id (ctx->self->priv->current_firmware));
  6106. g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
  6107. firmware_change_current_context_complete_and_free (ctx);
  6108. return;
  6109. }
  6110. /* Modem image ID */
  6111. tmp_len = 0;
  6112. tmp = (guint8 *)mm_utils_hexstr2bin (mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), &tmp_len);
  6113. modem_image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM;
  6114. modem_image_id.build_id = (gchar *)mm_firmware_properties_get_unique_id (ctx->firmware);
  6115. modem_image_id.unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len);
  6116. g_array_insert_vals (modem_image_id.unique_id, 0, tmp, tmp_len);
  6117. g_free (tmp);
  6118. /* PRI image ID */
  6119. tmp_len = 0;
  6120. tmp = (guint8 *)mm_utils_hexstr2bin (mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), &tmp_len);
  6121. pri_image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI;
  6122. pri_image_id.build_id = (gchar *)mm_firmware_properties_get_unique_id (ctx->firmware);
  6123. pri_image_id.unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len);
  6124. g_array_insert_vals (pri_image_id.unique_id, 0, tmp, tmp_len);
  6125. g_free (tmp);
  6126. mm_dbg ("Changing Gobi firmware to MODEM '%s' and PRI '%s' with Build ID '%s'...",
  6127. mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware),
  6128. mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware),
  6129. unique_id);
  6130. /* Build array of image IDs */
  6131. array = g_array_sized_new (FALSE, FALSE, sizeof (QmiMessageDmsSetFirmwarePreferenceInputListImage), 2);
  6132. g_array_append_val (array, modem_image_id);
  6133. g_array_append_val (array, pri_image_id);
  6134. input = qmi_message_dms_set_firmware_preference_input_new ();
  6135. qmi_message_dms_set_firmware_preference_input_set_list (input, array, NULL);
  6136. qmi_client_dms_set_firmware_preference (
  6137. ctx->client,
  6138. input,
  6139. 10,
  6140. NULL,
  6141. (GAsyncReadyCallback)firmware_select_stored_image_ready,
  6142. ctx);
  6143. g_array_unref (modem_image_id.unique_id);
  6144. g_array_unref (pri_image_id.unique_id);
  6145. qmi_message_dms_set_firmware_preference_input_unref (input);
  6146. }
  6147. /*****************************************************************************/
  6148. /* First enabling step */
  6149. static gboolean
  6150. enabling_started_finish (MMBroadbandModem *self,
  6151. GAsyncResult *res,
  6152. GError **error)
  6153. {
  6154. return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
  6155. }
  6156. static void
  6157. parent_enabling_started_ready (MMBroadbandModem *self,
  6158. GAsyncResult *res,
  6159. GSimpleAsyncResult *simple)
  6160. {
  6161. GError *error = NULL;
  6162. if (!MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->enabling_started_finish (
  6163. self,
  6164. res,
  6165. &error)) {
  6166. /* Don't treat this as fatal. Parent enabling may fail if it cannot grab a primary
  6167. * AT port, which isn't really an issue in QMI-based modems */
  6168. mm_dbg ("Couldn't start parent enabling: %s", error->message);
  6169. g_error_free (error);
  6170. }
  6171. g_simple_async_result_set_op_res_gboolean (simple, TRUE);
  6172. g_simple_async_result_complete (simple);
  6173. g_object_unref (simple);
  6174. }
  6175. static void
  6176. enabling_started (MMBroadbandModem *self,
  6177. GAsyncReadyCallback callback,
  6178. gpointer user_data)
  6179. {
  6180. GSimpleAsyncResult *result;
  6181. result = g_simple_async_result_new (G_OBJECT (self),
  6182. callback,
  6183. user_data,
  6184. enabling_started);
  6185. MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->enabling_started (
  6186. self,
  6187. (GAsyncReadyCallback)parent_enabling_started_ready,
  6188. result);
  6189. }
  6190. /*****************************************************************************/
  6191. /* First initialization step */
  6192. typedef struct {
  6193. MMBroadbandModem *self;
  6194. GSimpleAsyncResult *result;
  6195. MMQmiPort *qmi;
  6196. QmiService services[32];
  6197. guint service_index;
  6198. } InitializationStartedContext;
  6199. static void
  6200. initialization_started_context_complete_and_free (InitializationStartedContext *ctx)
  6201. {
  6202. g_simple_async_result_complete_in_idle (ctx->result);
  6203. if (ctx->qmi)
  6204. g_object_unref (ctx->qmi);
  6205. g_object_unref (ctx->result);
  6206. g_object_unref (ctx->self);
  6207. g_free (ctx);
  6208. }
  6209. static gpointer
  6210. initialization_started_finish (MMBroadbandModem *self,
  6211. GAsyncResult *res,
  6212. GError **error)
  6213. {
  6214. if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
  6215. return NULL;
  6216. /* Just parent's pointer passed here */
  6217. return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
  6218. }
  6219. static void
  6220. parent_initialization_started_ready (MMBroadbandModem *self,
  6221. GAsyncResult *res,
  6222. InitializationStartedContext *ctx)
  6223. {
  6224. gpointer parent_ctx;
  6225. GError *error = NULL;
  6226. parent_ctx = MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->initialization_started_finish (
  6227. self,
  6228. res,
  6229. &error);
  6230. if (error) {
  6231. /* Don't treat this as fatal. Parent initialization may fail if it cannot grab a primary
  6232. * AT port, which isn't really an issue in QMI-based modems */
  6233. mm_dbg ("Couldn't start parent initialization: %s", error->message);
  6234. g_error_free (error);
  6235. }
  6236. g_simple_async_result_set_op_res_gpointer (ctx->result, parent_ctx, NULL);
  6237. initialization_started_context_complete_and_free (ctx);
  6238. }
  6239. static void
  6240. parent_initialization_started (InitializationStartedContext *ctx)
  6241. {
  6242. MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->initialization_started (
  6243. ctx->self,
  6244. (GAsyncReadyCallback)parent_initialization_started_ready,
  6245. ctx);
  6246. }
  6247. static void allocate_next_client (InitializationStartedContext *ctx);
  6248. static void
  6249. qmi_port_allocate_client_ready (MMQmiPort *qmi,
  6250. GAsyncResult *res,
  6251. InitializationStartedContext *ctx)
  6252. {
  6253. GError *error = NULL;
  6254. if (!mm_qmi_port_allocate_client_finish (qmi, res, &error)) {
  6255. mm_dbg ("Couldn't allocate client for service '%s': %s",
  6256. qmi_service_get_string (ctx->services[ctx->service_index]),
  6257. error->message);
  6258. g_error_free (error);
  6259. }
  6260. ctx->service_index++;
  6261. allocate_next_client (ctx);
  6262. }
  6263. static void
  6264. allocate_next_client (InitializationStartedContext *ctx)
  6265. {
  6266. if (ctx->services[ctx->service_index] == QMI_SERVICE_UNKNOWN) {
  6267. /* Done we are, launch parent's callback */
  6268. parent_initialization_started (ctx);
  6269. return;
  6270. }
  6271. /* Otherwise, allocate next client */
  6272. mm_qmi_port_allocate_client (ctx->qmi,
  6273. ctx->services[ctx->service_index],
  6274. MM_QMI_PORT_FLAG_DEFAULT,
  6275. NULL,
  6276. (GAsyncReadyCallback)qmi_port_allocate_client_ready,
  6277. ctx);
  6278. }
  6279. static void
  6280. qmi_port_open_ready (MMQmiPort *qmi,
  6281. GAsyncResult *res,
  6282. InitializationStartedContext *ctx)
  6283. {
  6284. GError *error = NULL;
  6285. if (!mm_qmi_port_open_finish (qmi, res, &error)) {
  6286. g_simple_async_result_take_error (ctx->result, error);
  6287. initialization_started_context_complete_and_free (ctx);
  6288. return;
  6289. }
  6290. allocate_next_client (ctx);
  6291. }
  6292. static void
  6293. initialization_started (MMBroadbandModem *self,
  6294. GAsyncReadyCallback callback,
  6295. gpointer user_data)
  6296. {
  6297. InitializationStartedContext *ctx;
  6298. ctx = g_new0 (InitializationStartedContext, 1);
  6299. ctx->self = g_object_ref (self);
  6300. ctx->result = g_simple_async_result_new (G_OBJECT (self),
  6301. callback,
  6302. user_data,
  6303. initialization_started);
  6304. ctx->qmi = mm_base_modem_get_port_qmi (MM_BASE_MODEM (self));
  6305. /* This may happen if we unplug the modem unexpectedly */
  6306. if (!ctx->qmi) {
  6307. g_simple_async_result_set_error (ctx->result,
  6308. MM_CORE_ERROR,
  6309. MM_CORE_ERROR_FAILED,
  6310. "Cannot initialize: QMI port went missing");
  6311. initialization_started_context_complete_and_free (ctx);
  6312. return;
  6313. }
  6314. if (mm_qmi_port_is_open (ctx->qmi)) {
  6315. /* Nothing to be done, just launch parent's callback */
  6316. parent_initialization_started (ctx);
  6317. return;
  6318. }
  6319. /* Setup services to open */
  6320. ctx->services[0] = QMI_SERVICE_DMS;
  6321. ctx->services[1] = QMI_SERVICE_NAS;
  6322. ctx->services[2] = QMI_SERVICE_WMS;
  6323. ctx->services[3] = QMI_SERVICE_PDS;
  6324. ctx->services[4] = QMI_SERVICE_UNKNOWN;
  6325. /* Now open our QMI port */
  6326. mm_qmi_port_open (ctx->qmi,
  6327. TRUE,
  6328. NULL,
  6329. (GAsyncReadyCallback)qmi_port_open_ready,
  6330. ctx);
  6331. }
  6332. /*****************************************************************************/
  6333. MMBroadbandModemQmi *
  6334. mm_broadband_modem_qmi_new (const gchar *device,
  6335. const gchar **drivers,
  6336. const gchar *plugin,
  6337. guint16 vendor_id,
  6338. guint16 product_id)
  6339. {
  6340. return g_object_new (MM_TYPE_BROADBAND_MODEM_QMI,
  6341. MM_BASE_MODEM_DEVICE, device,
  6342. MM_BASE_MODEM_DRIVERS, drivers,
  6343. MM_BASE_MODEM_PLUGIN, plugin,
  6344. MM_BASE_MODEM_VENDOR_ID, vendor_id,
  6345. MM_BASE_MODEM_PRODUCT_ID, product_id,
  6346. NULL);
  6347. }
  6348. static void
  6349. mm_broadband_modem_qmi_init (MMBroadbandModemQmi *self)
  6350. {
  6351. /* Initialize private data */
  6352. self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
  6353. MM_TYPE_BROADBAND_MODEM_QMI,
  6354. MMBroadbandModemQmiPrivate);
  6355. }
  6356. static void
  6357. finalize (GObject *object)
  6358. {
  6359. MMQmiPort *qmi;
  6360. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (object);
  6361. qmi = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
  6362. /* If we did open the QMI port during initialization, close it now */
  6363. if (qmi &&
  6364. mm_qmi_port_is_open (qmi)) {
  6365. mm_qmi_port_close (qmi);
  6366. }
  6367. g_free (self->priv->imei);
  6368. g_free (self->priv->meid);
  6369. g_free (self->priv->esn);
  6370. g_free (self->priv->current_operator_id);
  6371. g_free (self->priv->current_operator_description);
  6372. if (self->priv->supported_bands)
  6373. g_array_unref (self->priv->supported_bands);
  6374. G_OBJECT_CLASS (mm_broadband_modem_qmi_parent_class)->finalize (object);
  6375. }
  6376. static void
  6377. dispose (GObject *object)
  6378. {
  6379. MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (object);
  6380. g_list_free_full (self->priv->firmware_list, (GDestroyNotify)g_object_unref);
  6381. self->priv->firmware_list = NULL;
  6382. g_clear_object (&self->priv->current_firmware);
  6383. G_OBJECT_CLASS (mm_broadband_modem_qmi_parent_class)->dispose (object);
  6384. }
  6385. static void
  6386. iface_modem_init (MMIfaceModem *iface)
  6387. {
  6388. /* Initialization steps */
  6389. iface->load_current_capabilities = modem_load_current_capabilities;
  6390. iface->load_current_capabilities_finish = modem_load_current_capabilities_finish;
  6391. iface->load_modem_capabilities = modem_load_modem_capabilities;
  6392. iface->load_modem_capabilities_finish = modem_load_modem_capabilities_finish;
  6393. iface->load_manufacturer = modem_load_manufacturer;
  6394. iface->load_manufacturer_finish = modem_load_manufacturer_finish;
  6395. iface->load_model = modem_load_model;
  6396. iface->load_model_finish = modem_load_model_finish;
  6397. iface->load_revision = modem_load_revision;
  6398. iface->load_revision_finish = modem_load_revision_finish;
  6399. iface->load_equipment_identifier = modem_load_equipment_identifier;
  6400. iface->load_equipment_identifier_finish = modem_load_equipment_identifier_finish;
  6401. iface->load_device_identifier = modem_load_device_identifier;
  6402. iface->load_device_identifier_finish = modem_load_device_identifier_finish;
  6403. iface->load_own_numbers = modem_load_own_numbers;
  6404. iface->load_own_numbers_finish = modem_load_own_numbers_finish;
  6405. iface->load_unlock_required = modem_load_unlock_required;
  6406. iface->load_unlock_required_finish = modem_load_unlock_required_finish;
  6407. iface->load_unlock_retries = modem_load_unlock_retries;
  6408. iface->load_unlock_retries_finish = modem_load_unlock_retries_finish;
  6409. iface->load_supported_bands = modem_load_supported_bands;
  6410. iface->load_supported_bands_finish = modem_load_supported_bands_finish;
  6411. iface->load_supported_modes = modem_load_supported_modes;
  6412. iface->load_supported_modes_finish = modem_load_supported_modes_finish;
  6413. iface->load_power_state = load_power_state;
  6414. iface->load_power_state_finish = load_power_state_finish;
  6415. /* Enabling/disabling */
  6416. iface->modem_power_up = modem_power_up;
  6417. iface->modem_power_up_finish = modem_power_up_down_finish;
  6418. iface->modem_after_power_up = NULL;
  6419. iface->modem_after_power_up_finish = NULL;
  6420. iface->modem_power_down = modem_power_down;
  6421. iface->modem_power_down_finish = modem_power_up_down_finish;
  6422. iface->setup_flow_control = NULL;
  6423. iface->setup_flow_control_finish = NULL;
  6424. iface->load_supported_charsets = NULL;
  6425. iface->load_supported_charsets_finish = NULL;
  6426. iface->setup_charset = NULL;
  6427. iface->setup_charset_finish = NULL;
  6428. iface->load_allowed_modes = load_allowed_modes;
  6429. iface->load_allowed_modes_finish = load_allowed_modes_finish;
  6430. iface->set_allowed_modes = set_allowed_modes;
  6431. iface->set_allowed_modes_finish = set_allowed_modes_finish;
  6432. iface->load_signal_quality = load_signal_quality;
  6433. iface->load_signal_quality_finish = load_signal_quality_finish;
  6434. iface->load_current_bands = modem_load_current_bands;
  6435. iface->load_current_bands_finish = modem_load_current_bands_finish;
  6436. iface->set_bands = set_bands;
  6437. iface->set_bands_finish = set_bands_finish;
  6438. /* Don't try to load access technologies, as we would be using parent's
  6439. * generic method (QCDM based). Access technologies are already reported via
  6440. * QMI when we load signal quality. */
  6441. iface->load_access_technologies = NULL;
  6442. iface->load_access_technologies_finish = NULL;
  6443. /* Create QMI-specific SIM */
  6444. iface->create_sim = create_sim;
  6445. iface->create_sim_finish = create_sim_finish;
  6446. /* Create QMI-specific bearer */
  6447. iface->create_bearer = modem_create_bearer;
  6448. iface->create_bearer_finish = modem_create_bearer_finish;
  6449. /* Other actions */
  6450. iface->factory_reset = modem_factory_reset;
  6451. iface->factory_reset_finish = modem_factory_reset_finish;
  6452. }
  6453. static void
  6454. iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
  6455. {
  6456. /* Initialization steps */
  6457. iface->load_imei = modem_3gpp_load_imei;
  6458. iface->load_imei_finish = modem_3gpp_load_imei_finish;
  6459. iface->load_enabled_facility_locks = modem_3gpp_load_enabled_facility_locks;
  6460. iface->load_enabled_facility_locks_finish = modem_3gpp_load_enabled_facility_locks_finish;
  6461. /* Enabling/Disabling steps */
  6462. iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events;
  6463. iface->setup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish;
  6464. iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events;
  6465. iface->cleanup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish;
  6466. iface->enable_unsolicited_events = modem_3gpp_enable_unsolicited_events;
  6467. iface->enable_unsolicited_events_finish = modem_3gpp_enable_disable_unsolicited_events_finish;
  6468. iface->disable_unsolicited_events = modem_3gpp_disable_unsolicited_events;
  6469. iface->disable_unsolicited_events_finish = modem_3gpp_enable_disable_unsolicited_events_finish;
  6470. iface->setup_unsolicited_registration_events = modem_3gpp_setup_unsolicited_registration_events;
  6471. iface->setup_unsolicited_registration_events_finish = modem_3gpp_setup_cleanup_unsolicited_registration_events_finish;
  6472. iface->cleanup_unsolicited_registration_events = modem_3gpp_cleanup_unsolicited_registration_events;
  6473. iface->cleanup_unsolicited_registration_events_finish = modem_3gpp_setup_cleanup_unsolicited_registration_events_finish;
  6474. iface->enable_unsolicited_registration_events = modem_3gpp_enable_unsolicited_registration_events;
  6475. iface->enable_unsolicited_registration_events_finish = modem_3gpp_enable_disable_unsolicited_registration_events_finish;
  6476. iface->disable_unsolicited_registration_events = modem_3gpp_disable_unsolicited_registration_events;
  6477. iface->disable_unsolicited_registration_events_finish = modem_3gpp_enable_disable_unsolicited_registration_events_finish;
  6478. /* Other actions */
  6479. iface->scan_networks = modem_3gpp_scan_networks;
  6480. iface->scan_networks_finish = modem_3gpp_scan_networks_finish;
  6481. iface->register_in_network = modem_3gpp_register_in_network;
  6482. iface->register_in_network_finish = modem_3gpp_register_in_network_finish;
  6483. iface->run_registration_checks = modem_3gpp_run_registration_checks;
  6484. iface->run_registration_checks_finish = modem_3gpp_run_registration_checks_finish;
  6485. iface->load_operator_code = modem_3gpp_load_operator_code;
  6486. iface->load_operator_code_finish = modem_3gpp_load_operator_code_finish;
  6487. iface->load_operator_name = modem_3gpp_load_operator_name;
  6488. iface->load_operator_name_finish = modem_3gpp_load_operator_name_finish;
  6489. }
  6490. static void
  6491. iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface)
  6492. {
  6493. /* Assume we don't have USSD support */
  6494. iface->check_support = NULL;
  6495. iface->check_support_finish = NULL;
  6496. }
  6497. static void
  6498. iface_modem_cdma_init (MMIfaceModemCdma *iface)
  6499. {
  6500. iface->load_meid = modem_cdma_load_meid;
  6501. iface->load_meid_finish = modem_cdma_load_meid_finish;
  6502. iface->load_esn = modem_cdma_load_esn;
  6503. iface->load_esn_finish = modem_cdma_load_esn_finish;
  6504. /* Enabling/Disabling steps */
  6505. iface->setup_unsolicited_events = modem_cdma_setup_unsolicited_events;
  6506. iface->setup_unsolicited_events_finish = modem_cdma_setup_cleanup_unsolicited_events_finish;
  6507. iface->cleanup_unsolicited_events = modem_cdma_cleanup_unsolicited_events;
  6508. iface->cleanup_unsolicited_events_finish = modem_cdma_setup_cleanup_unsolicited_events_finish;
  6509. iface->enable_unsolicited_events = modem_cdma_enable_unsolicited_events;
  6510. iface->enable_unsolicited_events_finish = modem_cdma_enable_disable_unsolicited_events_finish;
  6511. iface->disable_unsolicited_events = modem_cdma_disable_unsolicited_events;
  6512. iface->disable_unsolicited_events_finish = modem_cdma_enable_disable_unsolicited_events_finish;
  6513. /* Other actions */
  6514. iface->run_registration_checks = modem_cdma_run_registration_checks;
  6515. iface->run_registration_checks_finish = modem_cdma_run_registration_checks_finish;
  6516. }
  6517. static void
  6518. iface_modem_messaging_init (MMIfaceModemMessaging *iface)
  6519. {
  6520. iface->check_support = messaging_check_support;
  6521. iface->check_support_finish = messaging_check_support_finish;
  6522. iface->load_supported_storages = messaging_load_supported_storages;
  6523. iface->load_supported_storages_finish = messaging_load_supported_storages_finish;
  6524. iface->setup_sms_format = NULL;
  6525. iface->setup_sms_format_finish = NULL;
  6526. iface->set_default_storage = messaging_set_default_storage;
  6527. iface->set_default_storage_finish = messaging_set_default_storage_finish;
  6528. iface->load_initial_sms_parts = load_initial_sms_parts;
  6529. iface->load_initial_sms_parts_finish = load_initial_sms_parts_finish;
  6530. iface->setup_unsolicited_events = messaging_setup_unsolicited_events;
  6531. iface->setup_unsolicited_events_finish = messaging_setup_cleanup_unsolicited_events_finish;
  6532. iface->cleanup_unsolicited_events = messaging_cleanup_unsolicited_events;
  6533. iface->cleanup_unsolicited_events_finish = messaging_setup_cleanup_unsolicited_events_finish;
  6534. iface->enable_unsolicited_events = messaging_enable_unsolicited_events;
  6535. iface->enable_unsolicited_events_finish = messaging_enable_disable_unsolicited_events_finish;
  6536. iface->disable_unsolicited_events = messaging_disable_unsolicited_events;
  6537. iface->disable_unsolicited_events_finish = messaging_enable_disable_unsolicited_events_finish;
  6538. iface->create_sms = messaging_create_sms;
  6539. }
  6540. static void
  6541. iface_modem_location_init (MMIfaceModemLocation *iface)
  6542. {
  6543. iface_modem_location_parent = g_type_interface_peek_parent (iface);
  6544. iface->load_capabilities = location_load_capabilities;
  6545. iface->load_capabilities_finish = location_load_capabilities_finish;
  6546. iface->enable_location_gathering = enable_location_gathering;
  6547. iface->enable_location_gathering_finish = enable_location_gathering_finish;
  6548. iface->disable_location_gathering = disable_location_gathering;
  6549. iface->disable_location_gathering_finish = disable_location_gathering_finish;
  6550. }
  6551. static void
  6552. iface_modem_firmware_init (MMIfaceModemFirmware *iface)
  6553. {
  6554. iface->check_support = firmware_check_support;
  6555. iface->check_support_finish = firmware_check_support_finish;
  6556. iface->load_list = firmware_load_list;
  6557. iface->load_list_finish = firmware_load_list_finish;
  6558. iface->load_current = firmware_load_current;
  6559. iface->load_current_finish = firmware_load_current_finish;
  6560. iface->change_current = firmware_change_current;
  6561. iface->change_current_finish = firmware_change_current_finish;
  6562. }
  6563. static void
  6564. mm_broadband_modem_qmi_class_init (MMBroadbandModemQmiClass *klass)
  6565. {
  6566. GObjectClass *object_class = G_OBJECT_CLASS (klass);
  6567. MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
  6568. g_type_class_add_private (object_class, sizeof (MMBroadbandModemQmiPrivate));
  6569. object_class->finalize = finalize;
  6570. object_class->dispose = dispose;
  6571. broadband_modem_class->initialization_started = initialization_started;
  6572. broadband_modem_class->initialization_started_finish = initialization_started_finish;
  6573. broadband_modem_class->enabling_started = enabling_started;
  6574. broadband_modem_class->enabling_started_finish = enabling_started_finish;
  6575. /* Do not initialize the QMI modem through AT commands */
  6576. broadband_modem_class->enabling_modem_init = NULL;
  6577. broadband_modem_class->enabling_modem_init_finish = NULL;
  6578. }