1/*--------------------------------------------------------------------------
2Copyright (c) 2013, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are met:
6    * Redistributions of source code must retain the above copyright
7      notice, this list of conditions and the following disclaimer.
8    * Redistributions in binary form must reproduce the above copyright
9      notice, this list of conditions and the following disclaimer in the
10      documentation and/or other materials provided with the distribution.
11    * Neither the name of The Linux Foundation nor
12      the names of its contributors may be used to endorse or promote
13      products derived from this software without specific prior written
14      permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27--------------------------------------------------------------------------*/
28
29#ifdef WCNSS_QMI
30#define LOG_TAG "wcnss_qmi"
31#include <cutils/log.h>
32#include "wcnss_qmi_client.h"
33#include "qmi.h"
34#include "qmi_client.h"
35#include "device_management_service_v01.h"
36#include <cutils/properties.h>
37
38#define SUCCESS 0
39#define FAILED -1
40
41#define WLAN_ADDR_SIZE   6
42#define DMS_QMI_TIMEOUT (2000)
43
44static qmi_client_type dms_qmi_client;
45static int qmi_handle;
46static int dms_init_done = FAILED;
47
48/* Android system property for fetching the modem type */
49#define QMI_UIM_PROPERTY_BASEBAND               "ro.baseband"
50
51/* Android system property values for various modem types */
52#define QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_1     "svlte1"
53#define QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_2A    "svlte2a"
54#define QMI_UIM_PROP_BASEBAND_VALUE_CSFB        "csfb"
55#define QMI_UIM_PROP_BASEBAND_VALUE_SGLTE       "sglte"
56#define QMI_UIM_PROP_BASEBAND_VALUE_SGLTE2      "sglte2"
57#define QMI_UIM_PROP_BASEBAND_VALUE_MSM         "msm"
58#define QMI_UIM_PROP_BASEBAND_VALUE_APQ         "apq"
59#define QMI_UIM_PROP_BASEBAND_VALUE_MDMUSB      "mdm"
60#define QMI_UIM_PROP_BASEBAND_VALUE_DSDA        "dsda"
61#define QMI_UIM_PROP_BASEBAND_VALUE_DSDA_2      "dsda2"
62
63static char *dms_find_modem_port( char *prop_value_ptr)
64{
65	char *qmi_modem_port_ptr = QMI_PORT_RMNET_0;
66
67	/* Sanity check */
68	if (prop_value_ptr == NULL) {
69		ALOGE("%s", "NULL prop_value_ptr, using default port",
70			__func__);
71		return qmi_modem_port_ptr;
72	}
73
74	ALOGE("%s: Baseband property value read: %s", __func__,
75			prop_value_ptr);
76
77	/* Map the port based on the read property */
78	if ((strcmp(prop_value_ptr,
79		QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_1)  == 0) ||
80		(strcmp(prop_value_ptr,
81		QMI_UIM_PROP_BASEBAND_VALUE_SVLTE_2A) == 0) ||
82		(strcmp(prop_value_ptr,
83		QMI_UIM_PROP_BASEBAND_VALUE_CSFB) == 0)) {
84		qmi_modem_port_ptr = QMI_PORT_RMNET_SDIO_0;
85	} else if ((strcmp(prop_value_ptr,
86		QMI_UIM_PROP_BASEBAND_VALUE_MDMUSB) == 0) ||
87		(strcmp(prop_value_ptr,
88		QMI_UIM_PROP_BASEBAND_VALUE_SGLTE2) == 0)) {
89		qmi_modem_port_ptr = QMI_PORT_RMNET_USB_0;
90	} else if ((strcmp(prop_value_ptr,
91		QMI_UIM_PROP_BASEBAND_VALUE_MSM) == 0) ||
92		(strcmp(prop_value_ptr,
93		QMI_UIM_PROP_BASEBAND_VALUE_APQ) == 0) ||
94		(strcmp(prop_value_ptr,
95		QMI_UIM_PROP_BASEBAND_VALUE_SGLTE) == 0)) {
96		qmi_modem_port_ptr = QMI_PORT_RMNET_0;
97	} else if (strcmp(prop_value_ptr,
98		QMI_UIM_PROP_BASEBAND_VALUE_DSDA) == 0) {
99		/* If it is a DSDA configuration, use the existing API */
100		qmi_modem_port_ptr = (char *)QMI_PLATFORM_INTERNAL_USE_PORT_ID;
101	} else if (strcmp(prop_value_ptr,
102		QMI_UIM_PROP_BASEBAND_VALUE_DSDA_2) == 0) {
103		/* If it is a DSDA2 configuration, use the existing API */
104		qmi_modem_port_ptr = (char *)QMI_PLATFORM_INTERNAL_USE_PORT_ID;
105	} else {
106		ALOGE("%s: Property value does not match,using default port:%s",
107			__func__, qmi_modem_port_ptr);
108	}
109
110	ALOGE("%s: QMI port found for modem: %s", __func__, qmi_modem_port_ptr);
111
112	return qmi_modem_port_ptr;
113}
114
115int wcnss_init_qmi()
116{
117	qmi_client_error_type qmi_client_err;
118	qmi_idl_service_object_type dms_service;
119	char prop_value[PROPERTY_VALUE_MAX];
120	char *qmi_modem_port = NULL;
121
122	ALOGE("%s: Initialize wcnss QMI Interface", __func__);
123
124	qmi_handle = qmi_init(NULL, NULL);
125	if (qmi_handle < 0) {
126		ALOGE("%s: Error while initializing qmi", __func__);
127		return FAILED;
128	}
129
130	dms_service = dms_get_service_object_v01();
131	if (dms_service == NULL) {
132		ALOGE("%s: Not able to get the service handle", __func__);
133		goto exit;
134	}
135
136	/* Find out the modem type */
137	memset(prop_value, 0x00, sizeof(prop_value));
138	property_get(QMI_UIM_PROPERTY_BASEBAND, prop_value, "");
139
140	/* Map to a respective QMI port */
141	qmi_modem_port = dms_find_modem_port(prop_value);
142	if (qmi_modem_port == NULL) {
143		ALOGE("%s: qmi_modem_port is NULL", __func__);
144		goto exit;
145	}
146
147	qmi_client_err = qmi_client_init((const char *)qmi_modem_port,
148			dms_service, NULL, dms_service, &dms_qmi_client);
149
150	if ((qmi_client_err == QMI_PORT_NOT_OPEN_ERR) &&
151			(strcmp(qmi_modem_port, QMI_PORT_RMNET_0) == 0)){
152		ALOGE("%s: Retrying with port RMNET_1: %d",
153				__func__, qmi_client_err);
154		qmi_modem_port = QMI_PORT_RMNET_1;
155		qmi_client_err = qmi_client_init((const char *)qmi_modem_port,
156			       dms_service, NULL, dms_service, &dms_qmi_client);
157	}
158
159	if (qmi_client_err != QMI_NO_ERR){
160		ALOGE("%s: Error while Initializing QMI Client: %d",
161			__func__, qmi_client_err);
162		goto exit;
163	}
164
165	dms_init_done = SUCCESS;
166	return SUCCESS;
167
168exit:
169	qmi_handle = qmi_release(qmi_handle);
170	if ( qmi_handle < 0 )    {
171		ALOGE("%s: Error while releasing qmi %d",
172			 __func__, qmi_handle);
173	}
174	return FAILED;
175}
176
177int wcnss_qmi_get_wlan_address(unsigned char *pBdAddr)
178{
179	qmi_client_error_type qmi_client_err;
180	dms_get_mac_address_req_msg_v01 addr_req;
181	dms_get_mac_address_resp_msg_v01 addr_resp;
182
183	if ((dms_init_done == FAILED) || (pBdAddr == NULL)) {
184		ALOGE("%s: DMS init fail or pBdAddr is NULL", __func__);
185		return FAILED;
186	}
187
188	/* clear the request content */
189	memset(&addr_req, 0, sizeof(addr_req));
190
191	/*Request to get the WLAN MAC address */
192	addr_req.device = DMS_DEVICE_MAC_WLAN_V01;
193
194	qmi_client_err = qmi_client_send_msg_sync(dms_qmi_client,
195		QMI_DMS_GET_MAC_ADDRESS_REQ_V01, &addr_req, sizeof(addr_req),
196		&addr_resp, sizeof(addr_resp), DMS_QMI_TIMEOUT);
197
198	if (qmi_client_err != QMI_NO_ERR){
199		ALOGE("%s: Failed to get Rsp from Modem Error:%d",
200				__func__, qmi_client_err);
201		return FAILED;
202	}
203
204	ALOGE("%s: Mac Address_valid: %d Mac Address Len: %d",
205				__func__, addr_resp.mac_address_valid,
206				addr_resp.mac_address_len);
207
208	if (addr_resp.mac_address_valid &&
209		(addr_resp.mac_address_len == WLAN_ADDR_SIZE)) {
210		memcpy(pBdAddr, addr_resp.mac_address,
211			addr_resp.mac_address_len);
212		ALOGE("%s: Succesfully Read WLAN MAC Address", __func__);
213		return SUCCESS;
214	} else {
215		ALOGE("%s: Failed to Read WLAN MAC Address", __func__);
216		return FAILED;
217	}
218}
219
220void wcnss_qmi_deinit()
221{
222	qmi_client_error_type qmi_client_err;
223
224	ALOGE("%s: Deinitialize wcnss QMI Interface", __func__);
225
226	if (dms_init_done == FAILED) {
227		ALOGE("%s: DMS Service was not Initialized", __func__);
228		return;
229	}
230
231	qmi_client_err = qmi_client_release(dms_qmi_client);
232
233	if (qmi_client_err != QMI_NO_ERR){
234		ALOGE("%s: Error while releasing qmi_client: %d",
235			__func__, qmi_client_err);
236	}
237
238	qmi_handle = qmi_release(qmi_handle);
239	if (qmi_handle < 0)    {
240		ALOGE("%s: Error while releasing qmi %d",
241			__func__, qmi_handle);
242	}
243
244	dms_init_done = FAILED;
245}
246#endif
247