From: Antara <[email protected]>

adding coex driver for xmm7modem which uses intel  proprietory
AT commands. To enable/disable coex in modem and get bt and wifi
notifications. The driver will also be able to get the PLMN history.
---
 drivers/xmm7modem/coex.c | 641 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 641 insertions(+)
 create mode 100644 drivers/xmm7modem/coex.c

diff --git a/drivers/xmm7modem/coex.c b/drivers/xmm7modem/coex.c
new file mode 100644
index 0000000..fa0b0c4
--- /dev/null
+++ b/drivers/xmm7modem/coex.c
@@ -0,0 +1,641 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2016  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/modem.h>
+#include <ofono/log.h>
+#include <ofono/coex.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "xmm7modem.h"
+
+#define BAND_LEN 20
+static const char *xnvmplmn_prefix[] = { "+XNVMPLMN:", NULL };
+
+struct coex_data {
+       GAtChat *chat;
+       ofono_bool_t wlan_active;
+       enum ofono_wlan_bw wlan_bw;
+       ofono_bool_t bt_active;
+       ofono_bool_t wlan_active_pending;
+       enum ofono_wlan_bw wlan_bw_pending;
+       ofono_bool_t bt_active_pending;
+};
+
+enum xmm_net_band_lte {
+       NET_BAND_LTE_INVALID = 0,
+       NET_BAND_LTE_1 = 101,
+       NET_BAND_LTE_2,
+       NET_BAND_LTE_3,
+       NET_BAND_LTE_4,
+       NET_BAND_LTE_5,
+       NET_BAND_LTE_6,
+       NET_BAND_LTE_7,
+       NET_BAND_LTE_8,
+       NET_BAND_LTE_9,
+       NET_BAND_LTE_10,
+       NET_BAND_LTE_11,
+       NET_BAND_LTE_12,
+       NET_BAND_LTE_13,
+       NET_BAND_LTE_14,
+       NET_BAND_LTE_15,
+       NET_BAND_LTE_16,
+       NET_BAND_LTE_17,
+       NET_BAND_LTE_18,
+       NET_BAND_LTE_19,
+       NET_BAND_LTE_20,
+       NET_BAND_LTE_21,
+       NET_BAND_LTE_22,
+       NET_BAND_LTE_23,
+       NET_BAND_LTE_24,
+       NET_BAND_LTE_25,
+       NET_BAND_LTE_26,
+       NET_BAND_LTE_27,
+       NET_BAND_LTE_28,
+       NET_BAND_LTE_29,
+       NET_BAND_LTE_30,
+       NET_BAND_LTE_31,
+       NET_BAND_LTE_32,
+       NET_BAND_LTE_33,
+       NET_BAND_LTE_34,
+       NET_BAND_LTE_35,
+       NET_BAND_LTE_36,
+       NET_BAND_LTE_37,
+       NET_BAND_LTE_38,
+       NET_BAND_LTE_39,
+       NET_BAND_LTE_40,
+       NET_BAND_LTE_41,
+       NET_BAND_LTE_42,
+       NET_BAND_LTE_43 = 143
+};
+
+static const char *none_prefix[] = { NULL };
+
+static void xmm_set_bt_active_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data);
+
+static void xmm_set_wlan_active_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data);
+
+static void xmm_coex_l_notify(GAtResult *result, gpointer user_data)
+{
+       struct ofono_coex *coex = user_data;
+       GAtResultIter iter;
+       int lte_active;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+XNRTCWSL:"))
+               return;
+
+       if (!g_at_result_iter_next_number(&iter, &lte_active))
+               return;
+
+       DBG("lte_active:%d", lte_active);
+
+       ofono_lte_coex_status_notify(coex, lte_active);
+}
+
+void xmm_get_band_string(int lte_band, char* band)
+{
+       switch (lte_band) {
+               case NET_BAND_LTE_1:
+               strncpy(band,"BAND_LTE_1",BAND_LEN);
+               break;
+               case NET_BAND_LTE_2:
+               strncpy(band,"BAND_LTE_2",BAND_LEN);
+               break;
+               case NET_BAND_LTE_3:
+               strncpy(band,"BAND_LTE_3",BAND_LEN);
+               break;
+               case NET_BAND_LTE_4:
+               strncpy(band,"BAND_LTE_4",BAND_LEN);
+               break;
+               case NET_BAND_LTE_5:
+               strncpy(band,"BAND_LTE_5",BAND_LEN);
+               break;
+               case NET_BAND_LTE_6:
+               strncpy(band,"BAND_LTE_6",BAND_LEN);
+               break;
+               case NET_BAND_LTE_7:
+               strncpy(band,"BAND_LTE_7",BAND_LEN);
+               break;
+               case NET_BAND_LTE_8:
+               strncpy(band,"BAND_LTE_8",BAND_LEN);
+               break;
+               case NET_BAND_LTE_9:
+               strncpy(band,"BAND_LTE_9",BAND_LEN);
+               break;
+               case NET_BAND_LTE_10:
+               strncpy(band,"BAND_LTE_10",BAND_LEN);
+               break;
+               case NET_BAND_LTE_11:
+               strncpy(band,"BAND_LTE_11",BAND_LEN);
+               break;
+               case NET_BAND_LTE_12:
+               strncpy(band,"BAND_LTE_12",BAND_LEN);
+               break;
+               case NET_BAND_LTE_13:
+               strncpy(band,"BAND_LTE_13",BAND_LEN);
+               break;
+               case NET_BAND_LTE_14:
+               strncpy(band,"BAND_LTE_14",BAND_LEN);
+               break;
+               case NET_BAND_LTE_15:
+               strncpy(band,"BAND_LTE_15",BAND_LEN);
+               break;
+               case NET_BAND_LTE_16:
+               strncpy(band,"BAND_LTE_16",BAND_LEN);
+               break;
+               case NET_BAND_LTE_17:
+               strncpy(band,"BAND_LTE_17",BAND_LEN);
+               break;
+               case NET_BAND_LTE_18:
+               strncpy(band,"BAND_LTE_18",BAND_LEN);
+               break;
+               case NET_BAND_LTE_19:
+               strncpy(band,"BAND_LTE_19",BAND_LEN);
+               break;
+               case NET_BAND_LTE_20:
+               strncpy(band,"BAND_LTE_20",BAND_LEN);
+               break;
+               case NET_BAND_LTE_21:
+               strncpy(band,"BAND_LTE_21",BAND_LEN);
+               break;
+               case NET_BAND_LTE_22:
+               strncpy(band,"BAND_LTE_22",BAND_LEN);
+               break;
+               case NET_BAND_LTE_23:
+               strncpy(band,"BAND_LTE_23",BAND_LEN);
+               break;
+               case NET_BAND_LTE_24:
+               strncpy(band,"BAND_LTE_24",BAND_LEN);
+               break;
+               case NET_BAND_LTE_25:
+               strncpy(band,"BAND_LTE_25",BAND_LEN);
+               break;
+               case NET_BAND_LTE_26:
+               strncpy(band,"BAND_LTE_26",BAND_LEN);
+               break;
+               case NET_BAND_LTE_27:
+               strncpy(band,"BAND_LTE_27",BAND_LEN);
+               break;
+               case NET_BAND_LTE_28:
+               strncpy(band,"BAND_LTE_28",BAND_LEN);
+               break;
+               case NET_BAND_LTE_33:
+               strncpy(band,"BAND_LTE_33",BAND_LEN);
+               break;
+               case NET_BAND_LTE_34:
+               strncpy(band,"BAND_LTE_34",BAND_LEN);
+               break;
+               case NET_BAND_LTE_35:
+               strncpy(band,"BAND_LTE_35",BAND_LEN);
+               break;
+               case NET_BAND_LTE_36:
+               strncpy(band,"BAND_LTE_36",BAND_LEN);
+               break;
+               case NET_BAND_LTE_37:
+               strncpy(band,"BAND_LTE_37",BAND_LEN);
+               break;
+               case NET_BAND_LTE_38:
+               strncpy(band,"BAND_LTE_38",BAND_LEN);
+               break;
+               case NET_BAND_LTE_39:
+               strncpy(band,"BAND_LTE_39",BAND_LEN);
+               break;
+               case NET_BAND_LTE_40:
+               strncpy(band,"BAND_LTE_40",BAND_LEN);
+               break;
+               case NET_BAND_LTE_41:
+               strncpy(band,"BAND_LTE_41",BAND_LEN);
+               break;
+               case NET_BAND_LTE_42:
+               strncpy(band,"BAND_LTE_42",BAND_LEN);
+               break;
+               case NET_BAND_LTE_43:
+               strncpy(band,"BAND_LTE_43",BAND_LEN);
+               break;
+               default:
+               strncpy(band,"INVALID",BAND_LEN);
+               break;
+       }
+}
+
+static void xmm_lte_band_notify(GAtResult *result, gpointer user_data)
+{
+       struct ofono_coex *coex = user_data;
+       GAtResultIter iter;
+       int lte_band;
+       char band[BAND_LEN];
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+XCCINFO:"))
+               return;
+
+       g_at_result_iter_skip_next(&iter);
+       g_at_result_iter_skip_next(&iter);
+       g_at_result_iter_skip_next(&iter);
+       g_at_result_iter_skip_next(&iter);
+
+       if (!g_at_result_iter_next_number(&iter, &lte_band))
+               return;
+
+       xmm_get_band_string(lte_band, band);
+
+       DBG("lte_band:%s", band);
+       ofono_coex_ril_lte_band_notify(coex, band);
+}
+
+static void xmm_coex_w_notify(GAtResult *result, gpointer user_data)
+{
+       struct ofono_coex *coex = user_data;
+       GAtResultIter iter;
+       int safe_tx_min;
+       int safe_tx_max;
+       int safe_rx_min;
+       int safe_rx_max;
+       int safe_vector[MAX_BT_SAFE_VECTOR];
+       int num_safe_vector;
+       int count;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+XNRTCWSW:"))
+               return;
+
+       g_at_result_iter_next_number(&iter, &safe_rx_min);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_next_number(&iter, &safe_rx_max);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_next_number(&iter, &safe_tx_min);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_next_number(&iter, &safe_tx_max);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_skip_next(&iter);
+
+       g_at_result_iter_next_number(&iter, &num_safe_vector);
+
+       for(count = 0; count < num_safe_vector; count++) {
+               g_at_result_iter_next_number(&iter, &safe_vector[count]);
+       }
+
+       DBG("WLAN notification");
+
+       ofono_wlan_coex_status_notify(coex, safe_tx_min, safe_tx_max,
+               safe_rx_min, safe_rx_max,num_safe_vector,safe_vector);
+}
+
+
+static void xmm_coex_b_notify(GAtResult *result, gpointer user_data)
+{
+       struct ofono_coex *coex = user_data;
+       GAtResultIter iter;
+       int safe_tx_min;
+       int safe_tx_max;
+       int safe_rx_min;
+       int safe_rx_max;
+       int safe_vector[MAX_BT_SAFE_VECTOR];
+       int num_safe_vector;
+       int count;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+XNRTCWSB:"))
+               return;
+
+       g_at_result_iter_next_number(&iter, &safe_rx_min);
+
+       g_at_result_iter_next_number(&iter, &safe_rx_max);
+
+       g_at_result_iter_next_number(&iter, &safe_tx_min);
+
+       g_at_result_iter_next_number(&iter, &safe_tx_max);
+
+       g_at_result_iter_next_number(&iter, &num_safe_vector);
+
+       for(count = 0; count < num_safe_vector; count++) {
+               g_at_result_iter_next_number(&iter, &safe_vector[count]);
+       }
+
+       DBG("BT notification");
+
+       ofono_wlan_coex_status_notify(coex, safe_tx_min, safe_tx_max,
+               safe_rx_min, safe_rx_max,num_safe_vector,safe_vector);
+}
+
+static void xmm_coex_enable_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_coex_enable_cb_t cd = cbd->cb;
+
+       DBG("ok %d", ok);
+
+       if (!ok) {
+               struct ofono_error error;
+               decode_at_error(&error, g_at_result_final_response(result));
+               cd(&error, cbd->data);
+               return;
+       }
+
+       CALLBACK_WITH_SUCCESS(cd, cbd->data);
+}
+
+
+
+static void xmm_coex_enable(struct ofono_coex *coex,
+                       ofono_coex_enable_cb_t cb, void *data)
+{
+       struct coex_data *cd = ofono_coex_get_data(coex);
+       struct cb_data *cbd = cb_data_new(cb, data);
+
+       DBG("");
+
+       if(g_at_chat_send(cd->chat, "AT+XNRTCWS=7", none_prefix,
+                               xmm_coex_enable_cb, cbd, NULL) > 0)
+               return;
+
+       CALLBACK_WITH_FAILURE(cb, data);
+       g_free(cbd);
+}
+
+static int xmm_coex_probe(struct ofono_coex *coex, unsigned int vendor,
+                               void *user)
+{
+       GAtChat *chat = user;
+       struct coex_data *cd;
+
+       DBG("at coex probe");
+
+       cd = g_try_new0(struct coex_data, 1);
+       if (!cd)
+               return -ENOMEM;
+
+       cd->chat = g_at_chat_clone(chat);
+
+       ofono_coex_set_data(coex, cd);
+
+       g_at_chat_register(cd->chat, "+XNRTCWSL:", xmm_coex_l_notify,
+                                       FALSE, coex, NULL);
+       g_at_chat_register(cd->chat, "+XNRTCWSW:", xmm_coex_w_notify,
+                                       FALSE, coex, NULL);
+       g_at_chat_register(cd->chat, "+XNRTCWSB:", xmm_coex_b_notify,
+                                       FALSE, coex, NULL);
+       g_at_chat_register(cd->chat, "+XCCINFO:", xmm_lte_band_notify,
+                                       FALSE, coex, NULL);
+
+       g_at_chat_send(cd->chat, "AT+XCCINFO=1", none_prefix,
+                               NULL, NULL, NULL);
+       g_at_chat_send(cd->chat, "AT+XNRTAPP=10,100", none_prefix,
+                               NULL, NULL, NULL);
+
+       ofono_coex_register(coex);
+
+       return 0;
+}
+
+static void xmm_coex_remove_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_coex_enable_cb_t cd = cbd->cb;
+
+       DBG("ok %d", ok);
+
+       if (!ok) {
+               struct ofono_error error;
+               decode_at_error(&error, g_at_result_final_response(result));
+               cd(&error, cbd->data);
+               return;
+       }
+
+       CALLBACK_WITH_SUCCESS(cd, cbd->data);
+}
+
+
+static void xmm_coex_remove(struct ofono_coex *coex,
+                       ofono_coex_remove_cb_t cb, void *data)
+{
+       struct coex_data *cd = ofono_coex_get_data(coex);
+       struct cb_data *cbd = cb_data_new(cb, data);
+
+       DBG("");
+
+       if(g_at_chat_send(cd->chat, "AT+XNRTCWS=0", none_prefix,
+                               xmm_coex_remove_cb, cbd, NULL) > 0)
+               return;
+
+       CALLBACK_WITH_FAILURE(cb, data);
+       g_free(cbd);
+}
+
+static void xmm_set_bt_active_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_coex_enable_cb_t cd = cbd->cb;
+       struct coex_data* coex = ofono_coex_get_data(cbd->data);
+
+       DBG("ok %d", ok);
+
+       if (!ok) {
+               struct ofono_error error;
+               decode_at_error(&error, g_at_result_final_response(result));
+               cd(&error, cbd->data);
+               return;
+       }
+
+       coex->bt_active = coex->bt_active_pending;
+       CALLBACK_WITH_SUCCESS(cd, cbd->data);
+}
+
+
+
+static void xmm_set_bt_active(struct ofono_coex *coex, ofono_bool_t bt_active,
+                       ofono_coex_bt_active_set_cb_t cb, void *data)
+{
+       struct coex_data *cd = ofono_coex_get_data(coex);
+       struct cb_data *cbd = cb_data_new(cb, data);
+       char buf[64];
+
+       DBG("");
+       sprintf(buf, "AT+XNRTCWS=65535,%u,%u,%u", (int)cd->wlan_active,
+                               (int)cd->wlan_bw,bt_active);
+       if(g_at_chat_send(cd->chat, buf, none_prefix,
+                               xmm_set_bt_active_cb, cbd, NULL) > 0) {
+       cd->bt_active_pending = bt_active;
+               return;
+       }
+
+       CALLBACK_WITH_FAILURE(cb, data);
+       g_free(cbd);
+}
+
+
+static void xmm_set_wlan_active_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_coex_enable_cb_t cd = cbd->cb;
+       struct coex_data* coex = ofono_coex_get_data(cbd->data);
+
+       DBG("ok %d", ok);
+
+       if (!ok) {
+               struct ofono_error error;
+               decode_at_error(&error, g_at_result_final_response(result));
+               cd(&error, cbd->data);
+               return;
+       }
+
+       coex->wlan_active = coex->wlan_active_pending;
+       coex->wlan_bw = coex->wlan_bw_pending;
+       CALLBACK_WITH_SUCCESS(cd, cbd->data);
+}
+
+static void xmm_get_plmn_history_cb(gboolean ok, GAtResult *result,
+                                       gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_coex_get_plmn_history_cb_t cd = cbd->cb;
+       struct Plmnhist *list = NULL;
+       GAtResultIter iter;
+       int list_size = 0;
+
+       DBG("ok %d", ok);
+
+       if (!ok) {
+               CALLBACK_WITH_FAILURE(cd, 0, NULL, cbd->data);
+               return;
+       }
+
+       g_at_result_iter_init(&iter, result);
+
+       while (g_at_result_iter_next(&iter, "+XNVMPLMN:")) {
+               if (!list_size)
+                       list = g_new0(struct Plmnhist, ++list_size);
+               else
+                       list = g_renew(struct Plmnhist, list, ++list_size);
+
+               g_at_result_iter_next_number(&iter, (int*)&list[list_size - 
1].mcc);
+               g_at_result_iter_next_number(&iter, (int*)&list[list_size - 
1].mnc);
+               g_at_result_iter_next_number(&iter, (int*)&list[list_size - 
1].fdd);
+               g_at_result_iter_next_number(&iter, (int*)&list[list_size - 
1].tdd);
+               g_at_result_iter_next_number(&iter, (int*)&list[list_size - 
1].bw);
+
+               DBG("list_size = %d", list_size);
+       }
+
+       CALLBACK_WITH_SUCCESS(cd, list_size, list, cbd->data);
+       if(list)
+               g_free(list);
+}
+
+static void xmm_get_plmn_history(struct ofono_coex *coex,
+                       ofono_coex_get_plmn_history_cb_t cb, void *data)
+{
+       struct coex_data *cd = ofono_coex_get_data(coex);
+       struct cb_data *cbd = cb_data_new(cb, data);
+
+       DBG("");
+       if(g_at_chat_send(cd->chat, "AT+XNVMPLMN=2,2", xnvmplmn_prefix,
+                               xmm_get_plmn_history_cb, cbd, NULL) > 0) {
+               return;
+       }
+
+       CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+       g_free(cbd);
+}
+
+
+static void xmm_set_wlan_active(struct ofono_coex *coex,
+                       ofono_bool_t wlan_active, enum ofono_wlan_bw wlan_bw,
+                       ofono_coex_bt_active_set_cb_t cb, void *data)
+{
+       struct coex_data *cd = ofono_coex_get_data(coex);
+       struct cb_data *cbd = cb_data_new(cb, data);
+       char buf[64];
+
+       DBG("");
+       sprintf(buf, "AT+XNRTCWS=65535,%u,%u", (int)wlan_active,
+                               (int)wlan_bw);
+       if(g_at_chat_send(cd->chat, buf, none_prefix,
+                               xmm_set_wlan_active_cb, cbd, NULL) > 0) {
+               cd->wlan_active_pending = wlan_active;
+               cd->wlan_bw = wlan_bw;
+               return;
+       }
+
+       CALLBACK_WITH_FAILURE(cb, data);
+       g_free(cbd);
+}
+
+
+static struct ofono_coex_driver driver = {
+       .name = "xmm7modem",
+       .probe = xmm_coex_probe,
+       .enable = xmm_coex_enable,
+       .remove = xmm_coex_remove,
+       .set_bt_active = xmm_set_bt_active,
+       .set_wlan_active = xmm_set_wlan_active,
+       .get_plmn_history = xmm_get_plmn_history
+};
+
+void xmm_coex_init(void)
+{
+       ofono_coex_driver_register(&driver);
+}
+
+void xmm_coex_exit(void)
+{
+       ofono_coex_driver_unregister(&driver);
+}
-- 
1.9.1

_______________________________________________
ofono mailing list
[email protected]
https://lists.ofono.org/mailman/listinfo/ofono

Reply via email to