1 /*--------------------------------------------------------------------------
2 Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, 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 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 ADVISED 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 
44 static qmi_client_type dms_qmi_client;
45 static int qmi_handle;
46 static 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 
dms_find_modem_port(char * prop_value_ptr)63 static 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 
wcnss_init_qmi()115 int 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 
168 exit:
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 
wcnss_qmi_get_wlan_address(unsigned char * pBdAddr)177 int 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 
wcnss_qmi_deinit()220 void 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