xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/dhd_custom_cis.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Process CIS information from OTP for customer platform
3  * (Handle the MAC address and module information)
4  *
5  * Copyright (C) 2020, Broadcom.
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *
22  * <<Broadcom-WL-IPTag/Open:>>
23  *
24  * $Id$
25  */
26 
27 #include <typedefs.h>
28 #include <linuxver.h>
29 #include <osl.h>
30 
31 #include <ethernet.h>
32 #include <dngl_stats.h>
33 #include <bcmutils.h>
34 #include <dhd.h>
35 #include <dhd_dbg.h>
36 #include <dhd_linux.h>
37 #include <bcmdevs.h>
38 
39 #include <linux/fcntl.h>
40 #include <linux/fs.h>
41 #include <linux/list.h>
42 #include <bcmiov.h>
43 
44 #ifdef DHD_USE_CISINFO_FROM_OTP
45 #include <bcmdevs_legacy.h>    /* need to still support chips no longer in trunk firmware */
46 #include <siutils.h>
47 #include <pcie_core.h>
48 #include <dhd_pcie.h>
49 #endif /* DHD_USE_CISINFO_FROM_OTP */
50 
51 #ifdef DHD_USE_CISINFO_FROM_OTP
52 #define CIS_TUPLE_HDR_LEN		2
53 #if defined(BCM4375_CHIP)
54 #define CIS_TUPLE_START_ADDRESS     0x18011120
55 #define CIS_TUPLE_END_ADDRESS       0x18011177
56 #elif defined(BCM4389_CHIP_DEF)
57 #define CIS_TUPLE_START_ADDRESS     0x18011058
58 #define CIS_TUPLE_END_ADDRESS       0x180110AF
59 #else
60 #define CIS_TUPLE_START_ADDRESS     0x18011110
61 #define CIS_TUPLE_END_ADDRESS       0x18011167
62 #endif /* defined(BCM4375_CHIP) */
63 #define CIS_TUPLE_MAX_COUNT            (uint32)((CIS_TUPLE_END_ADDRESS - CIS_TUPLE_START_ADDRESS\
64 						+ 1) / sizeof(uint32))
65 #define CIS_TUPLE_TAG_START			0x80
66 #define CIS_TUPLE_TAG_VENDOR		0x81
67 #define CIS_TUPLE_TAG_BOARDTYPE		0x1b
68 #define CIS_TUPLE_TAG_LENGTH		1
69 
70 typedef struct cis_tuple_format {
71 	uint8	id;
72 	uint8	len;	/* total length of tag and data */
73 	uint8	tag;
74 	uint8	data[1];
75 } cis_tuple_format_t;
76 
77 static int
read_otp_from_bp(dhd_bus_t * bus,uint32 * data_buf)78 read_otp_from_bp(dhd_bus_t *bus, uint32 *data_buf)
79 {
80 	int int_val = 0, i = 0, bp_idx = 0;
81 	int boardtype_backplane_addr[] = {
82 		0x18010324, /* OTP Control 1 */
83 		0x18012618, /* PMU min resource mask */
84 	};
85 	int boardtype_backplane_data[] = {
86 		0x00fa0000,
87 		0x0e4fffff /* Keep on ARMHTAVAIL */
88 	};
89 
90 	uint32 cis_start_addr = CIS_TUPLE_START_ADDRESS;
91 	uint32 org_boardtype_backplane_data[] = {
92 		0,
93 		0
94 	};
95 
96 	for (bp_idx = 0; bp_idx < ARRAYSIZE(boardtype_backplane_addr); bp_idx++) {
97 		/* Read OTP Control 1 and PMU min_rsrc_mask before writing */
98 		if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int),
99 				&org_boardtype_backplane_data[bp_idx], TRUE) != BCME_OK) {
100 			DHD_ERROR(("invalid size/addr combination\n"));
101 			return BCME_ERROR;
102 		}
103 
104 		/* Write new OTP and PMU configuration */
105 		if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int),
106 				&boardtype_backplane_data[bp_idx], FALSE) != BCME_OK) {
107 			DHD_ERROR(("invalid size/addr combination\n"));
108 			return BCME_ERROR;
109 		}
110 
111 		if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int),
112 				&int_val, TRUE) != BCME_OK) {
113 			DHD_ERROR(("invalid size/addr combination\n"));
114 			return BCME_ERROR;
115 		}
116 
117 		DHD_INFO(("%s: boardtype_backplane_addr 0x%08x rdata 0x%04x\n",
118 			__FUNCTION__, boardtype_backplane_addr[bp_idx], int_val));
119 	}
120 
121 	/* read tuple raw data */
122 	for (i = 0; i < CIS_TUPLE_MAX_COUNT; i++) {
123 		if (si_backplane_access(bus->sih, cis_start_addr + i * sizeof(uint32),
124 				sizeof(uint32),	&data_buf[i], TRUE) != BCME_OK) {
125 			break;
126 		}
127 		DHD_INFO(("%s: tuple index %d, raw data 0x%08x\n", __FUNCTION__, i,  data_buf[i]));
128 	}
129 
130 	for (bp_idx = 0; bp_idx < ARRAYSIZE(boardtype_backplane_addr); bp_idx++) {
131 		/* Write original OTP and PMU configuration */
132 		if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int),
133 				&org_boardtype_backplane_data[bp_idx], FALSE) != BCME_OK) {
134 			DHD_ERROR(("invalid size/addr combination\n"));
135 			return BCME_ERROR;
136 		}
137 
138 		if (si_backplane_access(bus->sih, boardtype_backplane_addr[bp_idx], sizeof(int),
139 				&int_val, TRUE) != BCME_OK) {
140 			DHD_ERROR(("invalid size/addr combination\n"));
141 			return BCME_ERROR;
142 		}
143 
144 		DHD_INFO(("%s: boardtype_backplane_addr 0x%08x rdata 0x%04x\n",
145 			__FUNCTION__, boardtype_backplane_addr[bp_idx], int_val));
146 	}
147 
148 	return i * sizeof(uint32);
149 }
150 
151 static int
dhd_parse_board_information_bcm(dhd_bus_t * bus,int * boardtype,unsigned char * vid,int * vid_length)152 dhd_parse_board_information_bcm(dhd_bus_t *bus, int *boardtype,
153 		unsigned char *vid, int *vid_length)
154 {
155 	int totlen, len;
156 	uint32 raw_data[CIS_TUPLE_MAX_COUNT];
157 	cis_tuple_format_t *tuple;
158 
159 	totlen = read_otp_from_bp(bus, raw_data);
160 	if (totlen == BCME_ERROR || totlen == 0) {
161 		DHD_ERROR(("%s : Can't read the OTP\n", __FUNCTION__));
162 		return BCME_ERROR;
163 	}
164 
165 	tuple = (cis_tuple_format_t *)raw_data;
166 
167 	/* check the first tuple has tag 'start' */
168 	if (tuple->id != CIS_TUPLE_TAG_START) {
169 		DHD_ERROR(("%s: Can not find the TAG\n", __FUNCTION__));
170 		return BCME_ERROR;
171 	}
172 
173 	*vid_length = *boardtype = 0;
174 
175 	/* find tagged parameter */
176 	while ((totlen >= (tuple->len + CIS_TUPLE_HDR_LEN)) &&
177 			(*vid_length == 0 || *boardtype == 0)) {
178 		len = tuple->len;
179 
180 		if ((tuple->tag == CIS_TUPLE_TAG_VENDOR) &&
181 				(totlen >= (int)(len + CIS_TUPLE_HDR_LEN))) {
182 			/* found VID */
183 			memcpy(vid, tuple->data, tuple->len - CIS_TUPLE_TAG_LENGTH);
184 			*vid_length = tuple->len - CIS_TUPLE_TAG_LENGTH;
185 			prhex("OTP VID", tuple->data, tuple->len - CIS_TUPLE_TAG_LENGTH);
186 		}
187 		else if ((tuple->tag == CIS_TUPLE_TAG_BOARDTYPE) &&
188 				(totlen >= (int)(len + CIS_TUPLE_HDR_LEN))) {
189 			/* found boardtype */
190 			*boardtype = (int)tuple->data[0];
191 			prhex("OTP boardtype", tuple->data, tuple->len - CIS_TUPLE_TAG_LENGTH);
192 		}
193 
194 		tuple = (cis_tuple_format_t*)((uint8*)tuple + (len + CIS_TUPLE_HDR_LEN));
195 		totlen -= (len + CIS_TUPLE_HDR_LEN);
196 	}
197 
198 	if (*vid_length <= 0 || *boardtype <= 0) {
199 		DHD_ERROR(("failed to parse information (vid=%d, boardtype=%d)\n",
200 			*vid_length, *boardtype));
201 		return BCME_ERROR;
202 	}
203 
204 	return BCME_OK;
205 }
206 
207 #ifdef USE_CID_CHECK
208 #define CHIP_REV_A0	1
209 #define CHIP_REV_A1	2
210 #define CHIP_REV_B0	3
211 #define CHIP_REV_B1	4
212 #define CHIP_REV_B2	5
213 #define CHIP_REV_C0	6
214 #define BOARD_TYPE_EPA				0x080f
215 #define BOARD_TYPE_IPA				0x0827
216 #define BOARD_TYPE_IPA_OLD			0x081a
217 #define DEFAULT_CIDINFO_FOR_EPA		"r00a_e000_a0_ePA"
218 #define DEFAULT_CIDINFO_FOR_IPA		"r00a_e000_a0_iPA"
219 #define DEFAULT_CIDINFO_FOR_A1		"r01a_e30a_a1"
220 #define DEFAULT_CIDINFO_FOR_B0		"r01i_e32_b0"
221 
222 naming_info_t bcm4361_naming_table[] = {
223 	{ {""}, {""}, {""} },
224 	{ {"r00a_e000_a0_ePA"}, {"_a0_ePA"}, {"_a0_ePA"} },
225 	{ {"r00a_e000_a0_iPA"}, {"_a0"}, {"_a1"} },
226 	{ {"r01a_e30a_a1"}, {"_r01a_a1"}, {"_a1"} },
227 	{ {"r02a_e30a_a1"}, {"_r02a_a1"}, {"_a1"} },
228 	{ {"r02c_e30a_a1"}, {"_r02c_a1"}, {"_a1"} },
229 	{ {"r01d_e31_b0"}, {"_r01d_b0"}, {"_b0"} },
230 	{ {"r01f_e31_b0"}, {"_r01f_b0"}, {"_b0"} },
231 	{ {"r02g_e31_b0"}, {"_r02g_b0"}, {"_b0"} },
232 	{ {"r01h_e32_b0"}, {"_r01h_b0"}, {"_b0"} },
233 	{ {"r01i_e32_b0"}, {"_r01i_b0"}, {"_b0"} },
234 	{ {"r02j_e32_b0"}, {"_r02j_b0"}, {"_b0"} },
235 	{ {"r012_1kl_a1"}, {"_r012_a1"}, {"_a1"} },
236 	{ {"r013_1kl_b0"}, {"_r013_b0"}, {"_b0"} },
237 	{ {"r013_1kl_b0"}, {"_r013_b0"}, {"_b0"} },
238 	{ {"r014_1kl_b0"}, {"_r014_b0"}, {"_b0"} },
239 	{ {"r015_1kl_b0"}, {"_r015_b0"}, {"_b0"} },
240 	{ {"r020_1kl_b0"}, {"_r020_b0"}, {"_b0"} },
241 	{ {"r021_1kl_b0"}, {"_r021_b0"}, {"_b0"} },
242 	{ {"r022_1kl_b0"}, {"_r022_b0"}, {"_b0"} },
243 	{ {"r023_1kl_b0"}, {"_r023_b0"}, {"_b0"} },
244 	{ {"r024_1kl_b0"}, {"_r024_b0"}, {"_b0"} },
245 	{ {"r030_1kl_b0"}, {"_r030_b0"}, {"_b0"} },
246 	{ {"r031_1kl_b0"}, {"_r030_b0"}, {"_b0"} },	/* exceptional case : r31 -> r30 */
247 	{ {"r032_1kl_b0"}, {"_r032_b0"}, {"_b0"} },
248 	{ {"r033_1kl_b0"}, {"_r033_b0"}, {"_b0"} },
249 	{ {"r034_1kl_b0"}, {"_r034_b0"}, {"_b0"} },
250 	{ {"r02a_e32a_b2"}, {"_r02a_b2"}, {"_b2"} },
251 	{ {"r02b_e32a_b2"}, {"_r02b_b2"}, {"_b2"} },
252 	{ {"r020_1qw_b2"}, {"_r020_b2"}, {"_b2"} },
253 	{ {"r021_1qw_b2"}, {"_r021_b2"}, {"_b2"} },
254 	{ {"r022_1qw_b2"}, {"_r022_b2"}, {"_b2"} },
255 	{ {"r031_1qw_b2"}, {"_r031_b2"}, {"_b2"} }
256 };
257 
258 naming_info_t bcm4375_naming_table[] = {
259 	{ {""}, {""}, {""} },
260 	{ {"e41_es11"}, {"_ES00_semco_b0"}, {"_b0"} },
261 	{ {"e43_es33"}, {"_ES01_semco_b0"}, {"_b0"} },
262 	{ {"e43_es34"}, {"_ES02_semco_b0"}, {"_b0"} },
263 	{ {"e43_es35"}, {"_ES02_semco_b0"}, {"_b0"} },
264 	{ {"e43_es36"}, {"_ES03_semco_b0"}, {"_b0"} },
265 	{ {"e43_cs41"}, {"_CS00_semco_b1"}, {"_b1"} },
266 	{ {"e43_cs51"}, {"_CS01_semco_b1"}, {"_b1"} },
267 	{ {"e43_cs53"}, {"_CS01_semco_b1"}, {"_b1"} },
268 	{ {"e43_cs61"}, {"_CS00_skyworks_b1"}, {"_b1"} },
269 	{ {"1rh_es10"}, {"_1rh_es10_b0"}, {"_b0"} },
270 	{ {"1rh_es11"}, {"_1rh_es11_b0"}, {"_b0"} },
271 	{ {"1rh_es12"}, {"_1rh_es12_b0"}, {"_b0"} },
272 	{ {"1rh_es13"}, {"_1rh_es13_b0"}, {"_b0"} },
273 	{ {"1rh_es20"}, {"_1rh_es20_b0"}, {"_b0"} },
274 	{ {"1rh_es32"}, {"_1rh_es32_b0"}, {"_b0"} },
275 	{ {"1rh_es41"}, {"_1rh_es41_b1"}, {"_b1"} },
276 	{ {"1rh_es42"}, {"_1rh_es42_b1"}, {"_b1"} },
277 	{ {"1rh_es43"}, {"_1rh_es43_b1"}, {"_b1"} },
278 	{ {"1rh_es44"}, {"_1rh_es44_b1"}, {"_b1"} }
279 };
280 
281 naming_info_t bcm4389_naming_table[] = {
282 	{ {""}, {""}, {""} },
283 	{ {"e53_es23"}, {"_ES10_semco_b0"}, {"_b0"} },
284 	{ {"e53_es24"}, {"_ES20_semco_b0"}, {"_b0"} },
285 	{ {"e53_es25"}, {"_ES21_semco_b0"}, {"_b0"} },
286 	{ {"e53_es31"}, {"_ES30_semco_c0"}, {"_c0"} },
287 	{ {"e53_es32"}, {"_ES32_semco_c0"}, {"_c0"} },
288 	{ {"e53_es40"}, {"_ES40_semco_c1"}, {"_c1"} },
289 	{ {"1wk_es21"}, {"_1wk_es21_b0"}, {"_b0"} },
290 	{ {"1wk_es30"}, {"_1wk_es30_b0"}, {"_b0"} },
291 	{ {"1wk_es31"}, {"_1wk_es31_b0"}, {"_b0"} },
292 	{ {"1wk_es32"}, {"_1wk_es32_b0"}, {"_b0"} },
293 	{ {"1wk_es40"}, {"_1wk_es40_c0"}, {"_c0"} },
294 	{ {"1wk_es41"}, {"_1wk_es41_c0"}, {"_c0"} },
295 	{ {"1wk_es42"}, {"_1wk_es42_c0"}, {"_c0"} },
296 	{ {"1wk_es43"}, {"_1wk_es43_c0"}, {"_c0"} },
297 	{ {"1wk_es50"}, {"_1wk_es50_c1"}, {"_c1"} }
298 };
299 
300 /* select the NVRAM/FW tag naming table */
301 naming_info_t *
select_naming_table(dhd_pub_t * dhdp,int * table_size)302 select_naming_table(dhd_pub_t *dhdp, int *table_size)
303 {
304 	naming_info_t * info = NULL;
305 
306 	if (!dhdp || !dhdp->bus || !dhdp->bus->sih)
307 	{
308 		DHD_ERROR(("%s : Invalid pointer \n", __FUNCTION__));
309 		return info;
310 	}
311 
312 	switch (si_chipid(dhdp->bus->sih)) {
313 		case BCM4361_CHIP_ID:
314 		case BCM4347_CHIP_ID:
315 			info = &bcm4361_naming_table[0];
316 			*table_size = ARRAYSIZE(bcm4361_naming_table);
317 			DHD_INFO(("%s: info %p, ret %d\n", __FUNCTION__, info, *table_size));
318 			break;
319 		case BCM4375_CHIP_ID:
320 			info = &bcm4375_naming_table[0];
321 			*table_size = ARRAYSIZE(bcm4375_naming_table);
322 			DHD_INFO(("%s: info %p, ret %d\n", __FUNCTION__, info, *table_size));
323 			break;
324 		case BCM4389_CHIP_ID:
325 			info = &bcm4389_naming_table[0];
326 			*table_size = ARRAYSIZE(bcm4389_naming_table);
327 			DHD_INFO(("%s: info %p, ret %d\n", __FUNCTION__, info, *table_size));
328 			break;
329 		default:
330 			DHD_ERROR(("%s: No MODULE NAMING TABLE found\n", __FUNCTION__));
331 			break;
332 	}
333 
334 	return info;
335 }
336 
337 #define CID_FEM_MURATA				"_mur_"
338 naming_info_t *
dhd_find_naming_info(dhd_pub_t * dhdp,char * module_type)339 dhd_find_naming_info(dhd_pub_t *dhdp, char *module_type)
340 {
341 	int i = 0;
342 	naming_info_t *info = NULL;
343 	int table_size = 0;
344 
345 	info = select_naming_table(dhdp, &table_size);
346 	if (!info || !table_size) {
347 		DHD_ERROR(("%s : Can't select the naming table\n", __FUNCTION__));
348 		return NULL;
349 	}
350 
351 	if (module_type && strlen(module_type) > 0) {
352 		for (i = 1, info++; i < table_size; info++, i++) {
353 			DHD_INFO(("%s : info %p, %d, info->cid_ext : %s\n",
354 				__FUNCTION__, info, i, info->cid_ext));
355 			if (!strncmp(info->cid_ext, module_type, strlen(info->cid_ext))) {
356 				break;
357 			}
358 		}
359 	}
360 
361 	return info;
362 }
363 
364 static naming_info_t *
dhd_find_naming_info_by_cid(dhd_pub_t * dhdp,char * cid_info)365 dhd_find_naming_info_by_cid(dhd_pub_t *dhdp, char *cid_info)
366 {
367 	int i = 0;
368 	char *ptr;
369 	naming_info_t *info = NULL;
370 	int table_size = 0;
371 
372 	info = select_naming_table(dhdp, &table_size);
373 	if (!info || !table_size) {
374 		DHD_ERROR(("%s : Can't select the naming table\n", __FUNCTION__));
375 		return NULL;
376 	}
377 
378 	/* truncate extension */
379 	for (i = 1, ptr = cid_info; i < MODULE_NAME_INDEX_MAX && ptr; i++) {
380 		ptr = bcmstrstr(ptr, "_");
381 		if (ptr) {
382 			ptr++;
383 		}
384 	}
385 
386 	for (i = 1, info++; i < table_size && ptr; info++, i++) {
387 		DHD_INFO(("%s : info %p, %d, info->cid_ext : %s\n",
388 				__FUNCTION__, info, i, info->cid_ext));
389 		if (!strncmp(info->cid_ext, ptr, strlen(info->cid_ext))) {
390 			break;
391 		}
392 	}
393 
394 	return info;
395 }
396 
397 naming_info_t *
dhd_find_naming_info_by_chip_rev(dhd_pub_t * dhdp,bool * is_murata_fem)398 dhd_find_naming_info_by_chip_rev(dhd_pub_t *dhdp, bool *is_murata_fem)
399 {
400 	int board_type = 0, chip_rev = 0, vid_length = 0;
401 	unsigned char vid[MAX_VID_LEN];
402 	naming_info_t *info = NULL;
403 	char *cid_info = NULL;
404 	dhd_bus_t *bus = NULL;
405 
406 	if (!dhdp) {
407 		DHD_ERROR(("%s: dhdp is NULL \n", __FUNCTION__));
408 		return NULL;
409 	}
410 
411 	bus = dhdp->bus;
412 
413 	if (!bus || !bus->sih) {
414 		DHD_ERROR(("%s:bus(%p) or bus->sih is NULL\n", __FUNCTION__, bus));
415 		return NULL;
416 	}
417 
418 	chip_rev = bus->sih->chiprev;
419 
420 	if (dhd_parse_board_information_bcm(bus, &board_type, vid, &vid_length)
421 			!= BCME_OK) {
422 		DHD_ERROR(("%s:failed to parse board information\n", __FUNCTION__));
423 		return NULL;
424 	}
425 
426 	DHD_INFO(("%s:chip version %d\n", __FUNCTION__, chip_rev));
427 
428 #ifdef BCM4361_CHIP
429 	/* A0 chipset has exception only */
430 	if (chip_rev == CHIP_REV_A0) {
431 		if (board_type == BOARD_TYPE_EPA) {
432 			info = dhd_find_naming_info(dhdp, DEFAULT_CIDINFO_FOR_EPA);
433 		} else if ((board_type == BOARD_TYPE_IPA) ||
434 				(board_type == BOARD_TYPE_IPA_OLD)) {
435 			info = dhd_find_naming_info(dhdp, DEFAULT_CIDINFO_FOR_IPA);
436 		}
437 	} else
438 #endif /* BCM4361_CHIP */
439 	{
440 		cid_info = dhd_get_cid_info(vid, vid_length);
441 		if (cid_info) {
442 			info = dhd_find_naming_info_by_cid(dhdp, cid_info);
443 			if (strstr(cid_info, CID_FEM_MURATA)) {
444 				*is_murata_fem = TRUE;
445 			}
446 		}
447 	}
448 
449 	return info;
450 }
451 #endif /* USE_CID_CHECK */
452 #ifdef USE_DIRECT_VID_TAG
453 static int
concate_nvram_by_vid(dhd_pub_t * dhdp,char * nv_path,char * chipstr)454 concate_nvram_by_vid(dhd_pub_t *dhdp, char *nv_path, char *chipstr)
455 {
456 	unsigned char vid[MAX_VID_LEN];
457 	unsigned char vid2str[MAX_VID_LEN];
458 
459 	memset(vid, 0, sizeof(vid));
460 	memset(vid2str, 0, sizeof(vid2str));
461 
462 	if (dhd_check_stored_module_info(vid) == BCME_OK) {
463 		/* concate chip string tag */
464 		strncat(nv_path, chipstr, strlen(nv_path));
465 		/* concate nvram tag */
466 		snprintf(vid2str, sizeof(vid2str), "_%x%x", vid[VENDOR_OFF], vid[MD_REV_OFF]);
467 		strncat(nv_path, vid2str, strlen(nv_path));
468 		DHD_ERROR(("%s: nvram_path : %s\n", __FUNCTION__, nv_path));
469 	} else {
470 		int board_type = 0, vid_length = 0;
471 		dhd_bus_t *bus = NULL;
472 		if (!dhdp) {
473 
474 			DHD_ERROR(("%s : dhdp is NULL \n", __FUNCTION__));
475 			return BCME_ERROR;
476 		}
477 		bus = dhdp->bus;
478 		if (dhd_parse_board_information_bcm(bus, &board_type, vid, &vid_length)
479 				!= BCME_OK) {
480 			DHD_ERROR(("%s:failed to parse board information\n", __FUNCTION__));
481 			return BCME_ERROR;
482 		} else {
483 			/* concate chip string tag */
484 			strncat(nv_path, chipstr, strlen(nv_path));
485 			/* vid from CIS - vid[1] = vendor, vid[0] - module rev. */
486 			snprintf(vid2str, sizeof(vid2str), "_%x%x",
487 					vid[VENDOR_OFF], vid[MD_REV_OFF]);
488 			/* concate nvram tag */
489 			strncat(nv_path, vid2str, strlen(nv_path));
490 			DHD_ERROR(("%s: nvram_path : %s\n", __FUNCTION__, nv_path));
491 		}
492 	}
493 	return BCME_OK;
494 }
495 #endif /* USE_DIRECT_VID_TAG */
496 #endif /* DHD_USE_CISINFO_FROM_OTP */
497 
498 #ifdef DHD_USE_CISINFO
499 
500 /* File Location to keep each information */
501 #ifdef OEM_ANDROID
502 #define MACINFO PLATFORM_PATH".mac.info"
503 #define CIDINFO PLATFORM_PATH".cid.info"
504 #ifdef PLATFORM_SLP
505 #define MACINFO_EFS "/csa/.mac.info"
506 #else
507 #define MACINFO_EFS "/efs/wifi/.mac.info"
508 #define CIDINFO_DATA "/data/.cid.info"
509 #endif /* PLATFORM_SLP */
510 #else
511 #define MACINFO "/opt/.mac.info"
512 #define MACINFO_EFS "/opt/.efs.mac.info"
513 #define CIDINFO "/opt/.cid.info"
514 #endif /* OEM_ANDROID */
515 
516 /* Definitions for MAC address */
517 #define MAC_BUF_SIZE 20
518 #define MAC_CUSTOM_FORMAT	"%02X:%02X:%02X:%02X:%02X:%02X"
519 
520 /* Definitions for CIS information */
521 #if defined(BCM4359_CHIP) || defined(BCM4361_CHIP) || defined(BCM4375_CHIP) || \
522 	defined(BCM4389_CHIP_DEF)
523 #define CIS_BUF_SIZE            1280
524 #else
525 #define CIS_BUF_SIZE            512
526 #endif /* BCM4359_CHIP */
527 
528 #define DUMP_CIS_SIZE	48
529 
530 #define CIS_TUPLE_TAG_START		0x80
531 #define CIS_TUPLE_TAG_VENDOR		0x81
532 #define CIS_TUPLE_TAG_MACADDR		0x19
533 #define CIS_TUPLE_TAG_BOARDTYPE		0x1b
534 #define CIS_TUPLE_LEN_MACADDR		7
535 #define CIS_DUMP_END                    0xff
536 #define CIS_TUPLE_NULL                  0X00
537 
538 #ifdef CONFIG_BCMDHD_PCIE
539 #if defined(BCM4361_CHIP) || defined(BCM4375_CHIP)
540 #define OTP_OFFSET 208
541 #elif defined(BCM4389_CHIP_DEF)
542 #define OTP_OFFSET 0
543 #else
544 #define OTP_OFFSET 128
545 #endif /* BCM4361 | BCM4375 = 208, BCM4389 = 0, Others = 128 */
546 #else /* CONFIG_BCMDHD_PCIE */
547 #define OTP_OFFSET 12 /* SDIO */
548 #endif /* CONFIG_BCMDHD_PCIE */
549 
550 unsigned char *g_cis_buf = NULL;
551 
552 /* Definitions for common interface */
553 typedef struct tuple_entry {
554 	struct list_head list;	/* head of the list */
555 	uint32 cis_idx;		/* index of each tuples */
556 } tuple_entry_t;
557 
558 extern int _dhd_set_mac_address(struct dhd_info *dhd, int ifidx, struct ether_addr *addr);
559 #if defined(GET_MAC_FROM_OTP) || defined(USE_CID_CHECK)
560 static tuple_entry_t *dhd_alloc_tuple_entry(dhd_pub_t *dhdp, const int idx);
561 static void dhd_free_tuple_entry(dhd_pub_t *dhdp, struct list_head *head);
562 static int dhd_find_tuple_list_from_otp(dhd_pub_t *dhdp, int req_tup,
563 	unsigned char* req_tup_len, struct list_head *head);
564 #endif /* GET_MAC_FROM_OTP || USE_CID_CHECK */
565 
566 /* otp region read/write information */
567 typedef struct otp_rgn_rw_info {
568 	uint8 rgnid;
569 	uint8 preview;
570 	uint8 integrity_chk;
571 	uint16 rgnsize;
572 	uint16 datasize;
573 	uint8 *data;
574 } otp_rgn_rw_info_t;
575 
576 /* otp region status information */
577 typedef struct otp_rgn_stat_info {
578 	uint8 rgnid;
579 	uint16 rgnstart;
580 	uint16 rgnsize;
581 } otp_rgn_stat_info_t;
582 
583 typedef int (pack_handler_t)(void *ctx, uint8 *buf, uint16 *buflen);
584 
585 /* Common Interface Functions */
586 int
dhd_alloc_cis(dhd_pub_t * dhdp)587 dhd_alloc_cis(dhd_pub_t *dhdp)
588 {
589 	if (g_cis_buf == NULL) {
590 		g_cis_buf = MALLOCZ(dhdp->osh, CIS_BUF_SIZE);
591 		if (g_cis_buf == NULL) {
592 			DHD_ERROR(("%s: Failed to alloc buffer for CIS\n", __FUNCTION__));
593 			return BCME_NOMEM;
594 		} else {
595 			DHD_ERROR(("%s: Local CIS buffer is alloced\n", __FUNCTION__));
596 			memset(g_cis_buf, 0, CIS_BUF_SIZE);
597 		}
598 	}
599 	return BCME_OK;
600 }
601 
602 void
dhd_clear_cis(dhd_pub_t * dhdp)603 dhd_clear_cis(dhd_pub_t *dhdp)
604 {
605 	if (g_cis_buf) {
606 		MFREE(dhdp->osh, g_cis_buf, CIS_BUF_SIZE);
607 		g_cis_buf = NULL;
608 		DHD_ERROR(("%s: Local CIS buffer is freed\n", __FUNCTION__));
609 	}
610 }
611 
612 #ifdef DHD_READ_CIS_FROM_BP
613 int
dhd_read_cis(dhd_pub_t * dhdp)614 dhd_read_cis(dhd_pub_t *dhdp)
615 {
616 	int ret = 0, totlen = 0;
617 	uint32 raw_data[CIS_TUPLE_MAX_COUNT];
618 
619 	int cis_offset = OTP_OFFSET + sizeof(cis_rw_t);
620 #if defined(BCM4389_CHIP_DEF)
621 	/* override OTP_OFFSET for 4389 */
622 	cis_offset = OTP_OFFSET;
623 #endif /* BCM4389_CHIP_DEF */
624 
625 	totlen = read_otp_from_bp(dhdp->bus, raw_data);
626 	if (totlen == BCME_ERROR || totlen == 0) {
627 		DHD_ERROR(("%s : Can't read the OTP\n", __FUNCTION__));
628 		return BCME_ERROR;
629 	}
630 
631 	(void)memcpy_s(g_cis_buf + cis_offset, CIS_BUF_SIZE, raw_data, totlen);
632 	return ret;
633 }
634 #else
635 int
dhd_read_cis(dhd_pub_t * dhdp)636 dhd_read_cis(dhd_pub_t *dhdp)
637 {
638 	int ret = 0;
639 	cis_rw_t *cish;
640 	int buf_size = CIS_BUF_SIZE;
641 	int length = strlen("cisdump");
642 
643 	if (length >= buf_size) {
644 		DHD_ERROR(("%s: check CIS_BUF_SIZE\n", __FUNCTION__));
645 		return BCME_BADLEN;
646 	}
647 
648 	/* Try reading out from CIS */
649 	cish = (cis_rw_t *)(g_cis_buf + 8);
650 	cish->source = 0;
651 	cish->byteoff = 0;
652 	cish->nbytes = buf_size;
653 	strlcpy(g_cis_buf, "cisdump", buf_size);
654 
655 	ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, g_cis_buf, buf_size, 0, 0);
656 	if (ret < 0) {
657 		if (ret == BCME_UNSUPPORTED) {
658 			DHD_ERROR(("%s: get cisdump, UNSUPPORTED\n", __FUNCTION__));
659 		} else {
660 			DHD_ERROR(("%s : get cisdump err(%d)\n",
661 				__FUNCTION__, ret));
662 		}
663 		/* free local buf */
664 		dhd_clear_cis(dhdp);
665 	}
666 
667 	return ret;
668 }
669 #endif /* DHD_READ_CIS_FROM_BP */
670 
671 static int
dhd_otp_process_iov_resp_buf(void * ctx,void * iov_resp,uint16 cmd_id,bcm_xtlv_unpack_cbfn_t cbfn)672 dhd_otp_process_iov_resp_buf(void *ctx, void *iov_resp, uint16 cmd_id,
673 		bcm_xtlv_unpack_cbfn_t cbfn)
674 {
675 	bcm_iov_buf_t *p_resp = NULL;
676 	int ret = BCME_OK;
677 	uint16 version;
678 
679 	/* check for version */
680 	version = dtoh16(*(uint16 *)iov_resp);
681 	if (version != WL_OTP_IOV_VERSION) {
682 		return BCME_VERSION;
683 	}
684 
685 	p_resp = (bcm_iov_buf_t *)iov_resp;
686 	if ((p_resp->id == cmd_id) && (cbfn != NULL)) {
687 		ret = bcm_unpack_xtlv_buf(ctx, (uint8 *)p_resp->data, p_resp->len,
688 			BCM_XTLV_OPTION_ALIGN32, cbfn);
689 	}
690 
691 	return ret;
692 }
693 
694 static int
dhd_otp_get_iov_resp(dhd_pub_t * dhdp,const uint16 cmd_id,void * ctx,pack_handler_t packfn,bcm_xtlv_unpack_cbfn_t cbfn)695 dhd_otp_get_iov_resp(dhd_pub_t *dhdp, const uint16 cmd_id, void *ctx,
696 	pack_handler_t packfn, bcm_xtlv_unpack_cbfn_t cbfn)
697 {
698 	bcm_iov_buf_t *iov_buf = NULL;
699 	uint8 *iov_resp = NULL;
700 	int ret = BCME_OK;
701 	int buf_size = CIS_BUF_SIZE;
702 	uint16 iovlen = 0, buflen = 0, buflen_start = 0;
703 
704 	/* allocate input buffer */
705 	iov_buf = MALLOCZ(dhdp->osh, WLC_IOCTL_SMLEN);
706 	if (iov_buf == NULL) {
707 		DHD_ERROR(("%s: Failed to alloc buffer for iovar input\n", __FUNCTION__));
708 		ret = BCME_NOMEM;
709 		goto fail;
710 	}
711 
712 	iov_resp = MALLOCZ(dhdp->osh, WLC_IOCTL_MAXLEN);
713 	if (iov_resp == NULL) {
714 		DHD_ERROR(("%s: Failed to alloc buffer for iovar response\n", __FUNCTION__));
715 		ret = BCME_NOMEM;
716 		goto fail;
717 	}
718 
719 	/* parse and pack config parameters */
720 	buflen = buflen_start = (WLC_IOCTL_SMLEN - sizeof(*iov_buf));
721 	ret = packfn(ctx, (uint8 *)&iov_buf->data[0], &buflen);
722 	if (ret != BCME_OK) {
723 		goto fail;
724 	}
725 
726 	/* fill header portion */
727 	iov_buf->version = WL_OTP_IOV_VERSION;
728 	iov_buf->len = (buflen_start - buflen);
729 	iov_buf->id = cmd_id;
730 
731 	/* issue get iovar and process response */
732 	iovlen = sizeof(*iov_buf) + iov_buf->len;
733 	ret = dhd_iovar(dhdp, 0, "otp", (char *)iov_buf, iovlen,
734 			iov_resp, WLC_IOCTL_MAXLEN, FALSE);
735 	if (ret == BCME_OK) {
736 		ret = dhd_otp_process_iov_resp_buf(ctx, iov_resp, cmd_id, cbfn);
737 	} else {
738 		DHD_ERROR(("%s: Failed to get otp iovar\n", __FUNCTION__));
739 	}
740 
741 fail:
742 	if (iov_buf) {
743 		MFREE(dhdp->osh, iov_buf, WLC_IOCTL_SMLEN);
744 	}
745 	if (iov_resp) {
746 		MFREE(dhdp->osh, iov_resp, buf_size);
747 	}
748 	if (ret < 0) {
749 		/* free local buf */
750 		dhd_clear_cis(dhdp);
751 	}
752 	return ret;
753 }
754 
755 static int
dhd_otp_cbfn_rgnstatus(void * ctx,const uint8 * data,uint16 type,uint16 len)756 dhd_otp_cbfn_rgnstatus(void *ctx, const uint8 *data, uint16 type, uint16 len)
757 {
758 	otp_rgn_stat_info_t *stat_info = (otp_rgn_stat_info_t *)ctx;
759 
760 	BCM_REFERENCE(len);
761 
762 	if (data == NULL) {
763 		DHD_ERROR(("%s: bad argument !!!\n", __FUNCTION__));
764 		return BCME_BADARG;
765 	}
766 
767 	switch (type) {
768 		case WL_OTP_XTLV_RGN:
769 			stat_info->rgnid = *data;
770 			break;
771 		case WL_OTP_XTLV_ADDR:
772 			stat_info->rgnstart = dtoh16((uint16)*data);
773 			break;
774 		case WL_OTP_XTLV_SIZE:
775 			stat_info->rgnsize = dtoh16((uint16)*data);
776 			break;
777 		default:
778 			DHD_ERROR(("%s: unknown tlv %u\n", __FUNCTION__, type));
779 			break;
780 	}
781 
782 	return BCME_OK;
783 }
784 
785 static int
dhd_otp_packfn_rgnstatus(void * ctx,uint8 * buf,uint16 * buflen)786 dhd_otp_packfn_rgnstatus(void *ctx, uint8 *buf, uint16 *buflen)
787 {
788 	uint8 *pxtlv = buf;
789 	int ret = BCME_OK;
790 	uint16 len = *buflen;
791 	uint8 rgnid = OTP_RGN_SW;
792 
793 	BCM_REFERENCE(ctx);
794 
795 	/* pack option <-r region> */
796 	ret = bcm_pack_xtlv_entry(&pxtlv, &len, WL_OTP_XTLV_RGN, sizeof(rgnid),
797 			&rgnid, BCM_XTLV_OPTION_ALIGN32);
798 	if (ret != BCME_OK) {
799 		DHD_ERROR(("%s: Failed pack xtlv entry of region: %d\n", __FUNCTION__, ret));
800 		return ret;
801 	}
802 
803 	*buflen = len;
804 	return ret;
805 }
806 
807 static int
dhd_otp_packfn_rgndump(void * ctx,uint8 * buf,uint16 * buflen)808 dhd_otp_packfn_rgndump(void *ctx, uint8 *buf, uint16 *buflen)
809 {
810 	uint8 *pxtlv = buf;
811 	int ret = BCME_OK;
812 	uint16 len = *buflen, size = WLC_IOCTL_MAXLEN;
813 	uint8 rgnid = OTP_RGN_SW;
814 
815 	/* pack option <-r region> */
816 	ret = bcm_pack_xtlv_entry(&pxtlv, &len, WL_OTP_XTLV_RGN,
817 			sizeof(rgnid), &rgnid, BCM_XTLV_OPTION_ALIGN32);
818 	if (ret != BCME_OK) {
819 		DHD_ERROR(("%s: Failed pack xtlv entry of region: %d\n", __FUNCTION__, ret));
820 		goto fail;
821 	}
822 
823 	/* pack option [-s size] */
824 	ret = bcm_pack_xtlv_entry(&pxtlv, &len, WL_OTP_XTLV_SIZE,
825 			sizeof(size), (uint8 *)&size, BCM_XTLV_OPTION_ALIGN32);
826 	if (ret != BCME_OK) {
827 		DHD_ERROR(("%s: Failed pack xtlv entry of size: %d\n", __FUNCTION__, ret));
828 		goto fail;
829 	}
830 	*buflen = len;
831 fail:
832 	return ret;
833 }
834 
835 static int
dhd_otp_cbfn_rgndump(void * ctx,const uint8 * data,uint16 type,uint16 len)836 dhd_otp_cbfn_rgndump(void *ctx, const uint8 *data, uint16 type, uint16 len)
837 {
838 	otp_rgn_rw_info_t *rw_info = (otp_rgn_rw_info_t *)ctx;
839 
840 	BCM_REFERENCE(len);
841 
842 	if (data == NULL) {
843 		DHD_ERROR(("%s: bad argument !!!\n", __FUNCTION__));
844 		return BCME_BADARG;
845 	}
846 
847 	switch (type) {
848 		case WL_OTP_XTLV_RGN:
849 			rw_info->rgnid = *data;
850 			break;
851 		case WL_OTP_XTLV_DATA:
852 			/*
853 			 * intentionally ignoring the return value of memcpy_s as it is just
854 			 * a variable copy and because of this size is within the bounds
855 			 */
856 			(void)memcpy_s(&rw_info->data, sizeof(rw_info->data),
857 					&data, sizeof(rw_info->data));
858 			rw_info->datasize = len;
859 			break;
860 		default:
861 			DHD_ERROR(("%s: unknown tlv %u\n", __FUNCTION__, type));
862 			break;
863 	}
864 	return BCME_OK;
865 }
866 
867 int
dhd_read_otp_sw_rgn(dhd_pub_t * dhdp)868 dhd_read_otp_sw_rgn(dhd_pub_t *dhdp)
869 {
870 	int ret = BCME_OK;
871 	otp_rgn_rw_info_t rw_info;
872 	otp_rgn_stat_info_t stat_info;
873 
874 	memset(&rw_info, 0, sizeof(rw_info));
875 	memset(&stat_info, 0, sizeof(stat_info));
876 
877 	ret = dhd_otp_get_iov_resp(dhdp, WL_OTP_CMD_RGNSTATUS, &stat_info,
878 			dhd_otp_packfn_rgnstatus, dhd_otp_cbfn_rgnstatus);
879 	if (ret != BCME_OK) {
880 		DHD_ERROR(("%s: otp region status failed, ret=%d\n", __FUNCTION__, ret));
881 		goto fail;
882 	}
883 
884 	rw_info.rgnsize = stat_info.rgnsize;
885 	ret = dhd_otp_get_iov_resp(dhdp, WL_OTP_CMD_RGNDUMP, &rw_info,
886 			dhd_otp_packfn_rgndump, dhd_otp_cbfn_rgndump);
887 	if (ret != BCME_OK) {
888 		DHD_ERROR(("%s: otp region dump failed, ret=%d\n", __FUNCTION__, ret));
889 		goto fail;
890 	}
891 
892 	ret = memcpy_s(g_cis_buf, CIS_BUF_SIZE, rw_info.data, rw_info.datasize);
893 	if (ret != BCME_OK) {
894 		DHD_ERROR(("%s: Failed to copy otp dump, ret=%d\n", __FUNCTION__, ret));
895 	}
896 fail:
897 	return ret;
898 
899 }
900 
901 #if defined(GET_MAC_FROM_OTP) || defined(USE_CID_CHECK)
902 static tuple_entry_t*
dhd_alloc_tuple_entry(dhd_pub_t * dhdp,const int idx)903 dhd_alloc_tuple_entry(dhd_pub_t *dhdp, const int idx)
904 {
905 	tuple_entry_t *entry;
906 
907 	entry = MALLOCZ(dhdp->osh, sizeof(tuple_entry_t));
908 	if (!entry) {
909 		DHD_ERROR(("%s: failed to alloc entry\n", __FUNCTION__));
910 		return NULL;
911 	}
912 
913 	entry->cis_idx = idx;
914 
915 	return entry;
916 }
917 
918 static void
dhd_free_tuple_entry(dhd_pub_t * dhdp,struct list_head * head)919 dhd_free_tuple_entry(dhd_pub_t *dhdp, struct list_head *head)
920 {
921 	tuple_entry_t *entry;
922 
923 	while (!list_empty(head)) {
924 		entry = list_entry(head->next, tuple_entry_t, list);
925 		list_del(&entry->list);
926 
927 		MFREE(dhdp->osh, entry, sizeof(tuple_entry_t));
928 	}
929 }
930 
931 static int
dhd_find_tuple_list_from_otp(dhd_pub_t * dhdp,int req_tup,unsigned char * req_tup_len,struct list_head * head)932 dhd_find_tuple_list_from_otp(dhd_pub_t *dhdp, int req_tup,
933 	unsigned char* req_tup_len, struct list_head *head)
934 {
935 	int idx = OTP_OFFSET + sizeof(cis_rw_t);
936 	int tup, tup_len = 0;
937 	int buf_len = CIS_BUF_SIZE;
938 	int found = 0;
939 
940 #if defined(BCM4389_CHIP_DEF)
941 	/* override OTP_OFFEST for 4389 */
942 	idx = OTP_OFFSET;
943 #endif /* BCM4389_CHIP_DEF */
944 
945 	if (!g_cis_buf) {
946 		DHD_ERROR(("%s: Couldn't find cis info from"
947 			" local buffer\n", __FUNCTION__));
948 		return BCME_ERROR;
949 	}
950 
951 	do {
952 		tup = g_cis_buf[idx++];
953 		if (tup == CIS_TUPLE_NULL || tup == CIS_DUMP_END) {
954 			tup_len = 0;
955 		} else {
956 			tup_len = g_cis_buf[idx++];
957 			if ((idx + tup_len) > buf_len) {
958 				return BCME_ERROR;
959 			}
960 
961 			if (tup == CIS_TUPLE_TAG_START &&
962 				tup_len != CIS_TUPLE_NULL &&
963 				g_cis_buf[idx] == req_tup) {
964 				idx++;
965 				if (head) {
966 					tuple_entry_t *entry;
967 					entry = dhd_alloc_tuple_entry(dhdp, idx);
968 					if (entry) {
969 						list_add_tail(&entry->list, head);
970 						found++;
971 					}
972 				}
973 				if (found == 1 && req_tup_len) {
974 					*req_tup_len = tup_len;
975 				}
976 				tup_len--;
977 			}
978 		}
979 		idx += tup_len;
980 	} while (tup != CIS_DUMP_END && (idx < buf_len));
981 
982 	return (found > 0) ? found : BCME_ERROR;
983 }
984 #endif /* GET_MAC_FROM_OTP || USE_CID_CHECK */
985 
986 #ifdef DUMP_CIS
987 static void
dhd_dump_cis_buf(dhd_pub_t * dhdp,int size)988 dhd_dump_cis_buf(dhd_pub_t *dhdp, int size)
989 {
990 	int i;
991 	int cis_offset = 0;
992 
993 	cis_offset =  OTP_OFFSET + sizeof(cis_rw_t);
994 #if defined(BCM4389_CHIP_DEF)
995 	/* override OTP_OFFEST for 4389 */
996 	cis_offset = OTP_OFFSET;
997 #endif /* BCM4389_CHIP_DEF */
998 
999 	if (size <= 0) {
1000 		return;
1001 	}
1002 
1003 	if (size > CIS_BUF_SIZE) {
1004 		size = CIS_BUF_SIZE;
1005 	}
1006 
1007 	DHD_ERROR(("========== START CIS DUMP ==========\n"));
1008 	for (i = 0; i < size; i++) {
1009 		DHD_ERROR(("%02X ", g_cis_buf[i + cis_offset]));
1010 		if ((i % 16) == 15) {
1011 			DHD_ERROR(("\n"));
1012 		}
1013 	}
1014 	if ((i % 16) != 15) {
1015 		DHD_ERROR(("\n"));
1016 	}
1017 	DHD_ERROR(("========== END CIS DUMP ==========\n"));
1018 }
1019 #endif /* DUMP_CIS */
1020 
1021 /* MAC address mangement functions */
1022 #ifdef READ_MACADDR
1023 static void
dhd_create_random_mac(char * buf,unsigned int buf_len)1024 dhd_create_random_mac(char *buf, unsigned int buf_len)
1025 {
1026 	char random_mac[3];
1027 
1028 	memset(random_mac, 0, sizeof(random_mac));
1029 	get_random_bytes(random_mac, 3);
1030 
1031 	snprintf(buf, buf_len, MAC_CUSTOM_FORMAT, 0x00, 0x12, 0x34,
1032 		(uint32)random_mac[0], (uint32)random_mac[1], (uint32)random_mac[2]);
1033 
1034 	DHD_ERROR(("%s: The Random Generated MAC ID: %s\n",
1035 		__FUNCTION__, random_mac));
1036 }
1037 
1038 #ifndef DHD_MAC_ADDR_EXPORT
1039 int
dhd_set_macaddr_from_file(dhd_pub_t * dhdp)1040 dhd_set_macaddr_from_file(dhd_pub_t *dhdp)
1041 {
1042 	char mac_buf[MAC_BUF_SIZE];
1043 	char *filepath_efs = MACINFO_EFS;
1044 #ifdef PLATFORM_SLP
1045 	char *filepath_mac = MACINFO;
1046 #endif /* PLATFORM_SLP */
1047 	int ret;
1048 	struct dhd_info *dhd;
1049 	struct ether_addr *mac;
1050 	char *invalid_mac = "00:00:00:00:00:00";
1051 
1052 	if (dhdp) {
1053 		dhd = dhdp->info;
1054 		mac = &dhdp->mac;
1055 	} else {
1056 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
1057 		return BCME_ERROR;
1058 	}
1059 
1060 	memset(mac_buf, 0, sizeof(mac_buf));
1061 
1062 	/* Read MAC address from the specified file */
1063 	ret = dhd_read_file(filepath_efs, mac_buf, sizeof(mac_buf) - 1);
1064 
1065 	/* Check if the file does not exist or contains invalid data */
1066 	if (ret || (!ret && strstr(mac_buf, invalid_mac))) {
1067 		/* Generate a new random MAC address */
1068 		dhd_create_random_mac(mac_buf, sizeof(mac_buf));
1069 
1070 		/* Write random MAC address to the file */
1071 		if (dhd_write_file(filepath_efs, mac_buf, strlen(mac_buf)) < 0) {
1072 			DHD_ERROR(("%s: MAC address [%s] Failed to write into File:"
1073 				" %s\n", __FUNCTION__, mac_buf, filepath_efs));
1074 			return BCME_ERROR;
1075 		} else {
1076 			DHD_ERROR(("%s: MAC address [%s] written into File: %s\n",
1077 				__FUNCTION__, mac_buf, filepath_efs));
1078 		}
1079 	}
1080 #ifdef PLATFORM_SLP
1081 	/* Write random MAC address for framework */
1082 	if (dhd_write_file(filepath_mac, mac_buf, strlen(mac_buf)) < 0) {
1083 		DHD_ERROR(("%s: MAC address [%c%c:xx:xx:xx:x%c:%c%c] Failed to write into File:"
1084 			" %s\n", __FUNCTION__, mac_buf[0], mac_buf[1],
1085 			mac_buf[13], mac_buf[15], mac_buf[16], filepath_mac));
1086 	} else {
1087 		DHD_ERROR(("%s: MAC address [%c%c:xx:xx:xx:x%c:%c%c] written into File: %s\n",
1088 			__FUNCTION__, mac_buf[0], mac_buf[1], mac_buf[13],
1089 			mac_buf[15], mac_buf[16], filepath_mac));
1090 	}
1091 #endif /* PLATFORM_SLP */
1092 
1093 	mac_buf[sizeof(mac_buf) - 1] = '\0';
1094 
1095 	/* Write the MAC address to the Dongle */
1096 	sscanf(mac_buf, MAC_CUSTOM_FORMAT,
1097 		(uint32 *)&(mac->octet[0]), (uint32 *)&(mac->octet[1]),
1098 		(uint32 *)&(mac->octet[2]), (uint32 *)&(mac->octet[3]),
1099 		(uint32 *)&(mac->octet[4]), (uint32 *)&(mac->octet[5]));
1100 
1101 	if (_dhd_set_mac_address(dhd, 0, mac) == 0) {
1102 		DHD_INFO(("%s: MAC Address is overwritten\n", __FUNCTION__));
1103 	} else {
1104 		DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
1105 	}
1106 
1107 	return 0;
1108 }
1109 #else
1110 int
dhd_set_macaddr_from_file(dhd_pub_t * dhdp)1111 dhd_set_macaddr_from_file(dhd_pub_t *dhdp)
1112 {
1113 	char mac_buf[MAC_BUF_SIZE];
1114 
1115 	struct dhd_info *dhd;
1116 	struct ether_addr *mac;
1117 
1118 	if (dhdp) {
1119 		dhd = dhdp->info;
1120 		mac = &dhdp->mac;
1121 	} else {
1122 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
1123 		return BCME_ERROR;
1124 	}
1125 
1126 	memset(mac_buf, 0, sizeof(mac_buf));
1127 	if (ETHER_ISNULLADDR(&sysfs_mac_addr)) {
1128 		/* Generate a new random MAC address */
1129 		dhd_create_random_mac(mac_buf, sizeof(mac_buf));
1130 		if (!bcm_ether_atoe(mac_buf, &sysfs_mac_addr)) {
1131 			DHD_ERROR(("%s : mac parsing err\n", __FUNCTION__));
1132 			return BCME_ERROR;
1133 		}
1134 	}
1135 
1136 	/* Write the MAC address to the Dongle */
1137 	memcpy(mac, &sysfs_mac_addr, sizeof(sysfs_mac_addr));
1138 
1139 	if (_dhd_set_mac_address(dhd, 0, mac) == 0) {
1140 		DHD_INFO(("%s: MAC Address is overwritten\n", __FUNCTION__));
1141 	} else {
1142 		DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
1143 	}
1144 
1145 	return 0;
1146 }
1147 #endif /* !DHD_MAC_ADDR_EXPORT */
1148 #endif /* READ_MACADDR */
1149 
1150 #ifdef GET_MAC_FROM_OTP
1151 static int
dhd_set_default_macaddr(dhd_pub_t * dhdp)1152 dhd_set_default_macaddr(dhd_pub_t *dhdp)
1153 {
1154 	char iovbuf[WLC_IOCTL_SMLEN];
1155 	struct ether_addr *mac;
1156 	int ret;
1157 
1158 	if (!dhdp) {
1159 		DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
1160 		return BCME_BADARG;
1161 	}
1162 
1163 	mac = &dhdp->mac;
1164 
1165 	/* Read the default MAC address */
1166 	ret = dhd_iovar(dhdp, 0, "cur_etheraddr", NULL, 0, iovbuf, sizeof(iovbuf),
1167 			FALSE);
1168 	if (ret < 0) {
1169 		DHD_ERROR(("%s: Can't get the default MAC address\n", __FUNCTION__));
1170 		return BCME_NOTUP;
1171 	}
1172 
1173 	/* Update the default MAC address */
1174 	memcpy(mac, iovbuf, ETHER_ADDR_LEN);
1175 #ifdef DHD_MAC_ADDR_EXPORT
1176 	memcpy(&sysfs_mac_addr, mac, sizeof(sysfs_mac_addr));
1177 #endif /* DHD_MAC_ADDR_EXPORT */
1178 
1179 	return 0;
1180 }
1181 
1182 static int
dhd_verify_macaddr(dhd_pub_t * dhdp,struct list_head * head)1183 dhd_verify_macaddr(dhd_pub_t *dhdp, struct list_head *head)
1184 {
1185 	tuple_entry_t *cur, *next;
1186 	int idx = -1; /* Invalid index */
1187 
1188 	list_for_each_entry(cur, head, list) {
1189 		list_for_each_entry(next, &cur->list, list) {
1190 			if ((unsigned long)next == (unsigned long)head) {
1191 				DHD_INFO(("%s: next ptr %p is same as head ptr %p\n",
1192 					__FUNCTION__, next, head));
1193 				break;
1194 			}
1195 			if (!memcmp(&g_cis_buf[cur->cis_idx],
1196 				&g_cis_buf[next->cis_idx], ETHER_ADDR_LEN)) {
1197 				idx = cur->cis_idx;
1198 				break;
1199 			}
1200 		}
1201 	}
1202 
1203 	return idx;
1204 }
1205 
1206 int
dhd_check_module_mac(dhd_pub_t * dhdp)1207 dhd_check_module_mac(dhd_pub_t *dhdp)
1208 {
1209 #ifndef DHD_MAC_ADDR_EXPORT
1210 	char *filepath_efs = MACINFO_EFS;
1211 #endif /* !DHD_MAC_ADDR_EXPORT */
1212 	unsigned char otp_mac_buf[MAC_BUF_SIZE];
1213 	struct ether_addr *mac;
1214 	struct dhd_info *dhd;
1215 
1216 	if (!dhdp) {
1217 		DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
1218 		return BCME_BADARG;
1219 	}
1220 
1221 	dhd = dhdp->info;
1222 	if (!dhd) {
1223 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
1224 		return BCME_BADARG;
1225 	}
1226 
1227 #if defined(DHD_READ_CIS_FROM_BP) && defined(READ_MACADDR)
1228 	/*
1229 	 * For KOR Module, CID update is required only
1230 	 * so, clearing and making g_cis_buf = NULL  before processing it when read_cis from STA FW
1231 	 * It will get MAC from sysfs && won't update sysfs mac
1232 	 */
1233 	if (dhd_bus_get_fw_mode(dhdp) == DHD_FLAG_STA_MODE) {
1234 		dhd_clear_cis(dhdp);
1235 	}
1236 #endif /* DHD_READ_CIS_FROM_BP && READ_MACADDR  */
1237 
1238 	mac = &dhdp->mac;
1239 	memset(otp_mac_buf, 0, sizeof(otp_mac_buf));
1240 
1241 	if (!g_cis_buf) {
1242 #ifndef DHD_MAC_ADDR_EXPORT
1243 		char eabuf[ETHER_ADDR_STR_LEN];
1244 		DHD_INFO(("%s: Couldn't read CIS information\n", __FUNCTION__));
1245 
1246 		/* Read the MAC address from the specified file */
1247 		if (dhd_read_file(filepath_efs, otp_mac_buf, sizeof(otp_mac_buf) - 1) < 0) {
1248 			DHD_ERROR(("%s: Couldn't read the file, "
1249 				"use the default MAC Address\n", __FUNCTION__));
1250 			if (dhd_set_default_macaddr(dhdp) < 0) {
1251 				return BCME_BADARG;
1252 			}
1253 		} else {
1254 			bzero((char *)eabuf, sizeof(eabuf));
1255 			strlcpy(eabuf, otp_mac_buf, sizeof(eabuf));
1256 			if (!bcm_ether_atoe(eabuf, mac)) {
1257 				DHD_ERROR(("%s : mac parsing err\n", __FUNCTION__));
1258 				if (dhd_set_default_macaddr(dhdp) < 0) {
1259 					return BCME_BADARG;
1260 				}
1261 			}
1262 		}
1263 #else
1264 		DHD_INFO(("%s: Couldn't read CIS information\n", __FUNCTION__));
1265 
1266 		/* Read the MAC address from the specified file */
1267 		if (ETHER_ISNULLADDR(&sysfs_mac_addr)) {
1268 			DHD_ERROR(("%s: Couldn't read the file, "
1269 				"use the default MAC Address\n", __FUNCTION__));
1270 			if (dhd_set_default_macaddr(dhdp) < 0) {
1271 				return BCME_BADARG;
1272 			}
1273 		} else {
1274 			/* sysfs mac addr is confirmed with valid format in set_mac_addr */
1275 			memcpy(mac, &sysfs_mac_addr, sizeof(sysfs_mac_addr));
1276 		}
1277 #endif /* !DHD_MAC_ADDR_EXPORT */
1278 	} else {
1279 		struct list_head mac_list;
1280 		unsigned char tuple_len = 0;
1281 		int found = 0;
1282 		int idx = -1; /* Invalid index */
1283 
1284 #ifdef DUMP_CIS
1285 		dhd_dump_cis_buf(dhdp, DUMP_CIS_SIZE);
1286 #endif /* DUMP_CIS */
1287 
1288 		/* Find a new tuple tag */
1289 		INIT_LIST_HEAD(&mac_list);
1290 		found = dhd_find_tuple_list_from_otp(dhdp, CIS_TUPLE_TAG_MACADDR,
1291 			&tuple_len, &mac_list);
1292 		if ((found > 0) && tuple_len == CIS_TUPLE_LEN_MACADDR) {
1293 			if (found == 1) {
1294 				tuple_entry_t *cur = list_entry((&mac_list)->next,
1295 					tuple_entry_t, list);
1296 				idx = cur->cis_idx;
1297 			} else {
1298 				/* Find the start index of MAC address */
1299 				idx = dhd_verify_macaddr(dhdp, &mac_list);
1300 			}
1301 		}
1302 
1303 		/* Find the MAC address */
1304 		if (idx > 0) {
1305 #ifdef DHD_EXPORT_CNTL_FILE
1306 			/*
1307 			 * WAR for incorrect otp mac address (including multicast bit)
1308 			 * for SEMCo e53_es31 module
1309 			 */
1310 			if (strcmp(cidinfostr, "semco_sem_e53_es31") == 0) {
1311 				g_cis_buf[idx] &= 0xFE;
1312 			}
1313 #endif /* DHD_EXPORT_CNTL_FILE */
1314 			/* update MAC address */
1315 			snprintf(otp_mac_buf, sizeof(otp_mac_buf), MAC_CUSTOM_FORMAT,
1316 				(uint32)g_cis_buf[idx], (uint32)g_cis_buf[idx + 1],
1317 				(uint32)g_cis_buf[idx + 2], (uint32)g_cis_buf[idx + 3],
1318 				(uint32)g_cis_buf[idx + 4], (uint32)g_cis_buf[idx + 5]);
1319 			DHD_ERROR(("%s: MAC address is taken from OTP: " MACDBG "\n",
1320 				__FUNCTION__, MAC2STRDBG(&g_cis_buf[idx])));
1321 		} else {
1322 			/* Not found MAC address info from the OTP, use the default value */
1323 			if (dhd_set_default_macaddr(dhdp) < 0) {
1324 				dhd_free_tuple_entry(dhdp, &mac_list);
1325 				return BCME_BADARG;
1326 			}
1327 			snprintf(otp_mac_buf, sizeof(otp_mac_buf), MAC_CUSTOM_FORMAT,
1328 				(uint32)mac->octet[0], (uint32)mac->octet[1],
1329 				(uint32)mac->octet[2], (uint32)mac->octet[3],
1330 				(uint32)mac->octet[4], (uint32)mac->octet[5]);
1331 			DHD_ERROR(("%s: Cannot find MAC address info from OTP,"
1332 				" Check module mac by initial value: " MACDBG "\n",
1333 				__FUNCTION__, MAC2STRDBG(mac->octet)));
1334 		}
1335 
1336 		dhd_free_tuple_entry(dhdp, &mac_list);
1337 #ifndef DHD_MAC_ADDR_EXPORT
1338 		dhd_write_file(filepath_efs, otp_mac_buf, strlen(otp_mac_buf));
1339 #else
1340 		/* Export otp_mac_buf to the sys/mac_addr */
1341 		if (!bcm_ether_atoe(otp_mac_buf, &sysfs_mac_addr)) {
1342 			DHD_ERROR(("%s : mac parsing err\n", __FUNCTION__));
1343 			if (dhd_set_default_macaddr(dhdp) < 0) {
1344 				return BCME_BADARG;
1345 			}
1346 		} else {
1347 			DHD_INFO(("%s : set mac address properly\n", __FUNCTION__));
1348 			/* set otp mac to sysfs */
1349 			memcpy(mac, &sysfs_mac_addr, sizeof(sysfs_mac_addr));
1350 		}
1351 #endif /* !DHD_MAC_ADDR_EXPORT */
1352 	}
1353 
1354 	if (_dhd_set_mac_address(dhd, 0, mac) == 0) {
1355 		DHD_INFO(("%s: MAC Address is set\n", __FUNCTION__));
1356 	} else {
1357 		DHD_ERROR(("%s: Failed to set MAC address\n", __FUNCTION__));
1358 	}
1359 
1360 	return 0;
1361 }
1362 #endif /* GET_MAC_FROM_OTP */
1363 
1364 /*
1365  * XXX:SWWLAN-210178 SysFS MAC ADDR export
1366  * framework controls mac addr with sysfs mac_addr kernel object without file system
1367  * For this reason, DHD doesn't need to write mac address to file system directly
1368  */
1369 #ifndef DHD_MAC_ADDR_EXPORT
1370 #ifdef WRITE_MACADDR
1371 int
dhd_write_macaddr(struct ether_addr * mac)1372 dhd_write_macaddr(struct ether_addr *mac)
1373 {
1374 	char *filepath_data = MACINFO;
1375 	char *filepath_efs = MACINFO_EFS;
1376 	char mac_buf[MAC_BUF_SIZE];
1377 	int ret = 0;
1378 	int retry_cnt = 0;
1379 
1380 	memset(mac_buf, 0, sizeof(mac_buf));
1381 	snprintf(mac_buf, sizeof(mac_buf), MAC_CUSTOM_FORMAT,
1382 		(uint32)mac->octet[0], (uint32)mac->octet[1],
1383 		(uint32)mac->octet[2], (uint32)mac->octet[3],
1384 		(uint32)mac->octet[4], (uint32)mac->octet[5]);
1385 
1386 	if (filepath_data) {
1387 		for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) {
1388 			/* Write MAC information into /data/.mac.info */
1389 			ret = dhd_write_file_and_check(filepath_data, mac_buf, strlen(mac_buf));
1390 			if (!ret) {
1391 				break;
1392 			}
1393 		}
1394 
1395 		if (ret < 0) {
1396 			DHD_ERROR(("%s: MAC address [%s] Failed to write into"
1397 				" File: %s\n", __FUNCTION__, mac_buf, filepath_data));
1398 			return BCME_ERROR;
1399 		}
1400 	} else {
1401 		DHD_ERROR(("%s: filepath_data doesn't exist\n", __FUNCTION__));
1402 	}
1403 
1404 	if (filepath_efs) {
1405 		for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) {
1406 			/* Write MAC information into /efs/wifi/.mac.info */
1407 			ret = dhd_write_file_and_check(filepath_efs, mac_buf, strlen(mac_buf));
1408 			if (!ret) {
1409 				break;
1410 			}
1411 		}
1412 
1413 		if (ret < 0) {
1414 			DHD_ERROR(("%s: MAC address [%s] Failed to write into"
1415 				" File: %s\n", __FUNCTION__, mac_buf, filepath_efs));
1416 			return BCME_ERROR;
1417 		}
1418 	} else {
1419 		DHD_ERROR(("%s: filepath_efs doesn't exist\n", __FUNCTION__));
1420 	}
1421 
1422 	return ret;
1423 }
1424 #endif /* WRITE_MACADDR */
1425 #endif /* !DHD_MAC_ADDR_EXPORT */
1426 
1427 #if defined(USE_CID_CHECK) || defined(USE_DIRECT_VID_TAG)
1428 static int
dhd_find_tuple_idx_from_otp(dhd_pub_t * dhdp,int req_tup,unsigned char * req_tup_len)1429 dhd_find_tuple_idx_from_otp(dhd_pub_t *dhdp, int req_tup, unsigned char *req_tup_len)
1430 {
1431 	struct list_head head;
1432 	int start_idx;
1433 	int entry_num;
1434 
1435 	if (!g_cis_buf) {
1436 		DHD_ERROR(("%s: Couldn't find cis info from"
1437 			" local buffer\n", __FUNCTION__));
1438 		return BCME_ERROR;
1439 	}
1440 
1441 	INIT_LIST_HEAD(&head);
1442 	entry_num = dhd_find_tuple_list_from_otp(dhdp, req_tup, req_tup_len, &head);
1443 	/* find the first cis index from the tuple list */
1444 	if (entry_num > 0) {
1445 		tuple_entry_t *cur = list_entry((&head)->next, tuple_entry_t, list);
1446 		start_idx = cur->cis_idx;
1447 	} else {
1448 		start_idx = -1; /* Invalid index */
1449 	}
1450 
1451 	dhd_free_tuple_entry(dhdp, &head);
1452 
1453 	return start_idx;
1454 }
1455 #endif /* USE_CID_CHECK || USE_DIRECT_VID_TAG */
1456 
1457 #ifdef USE_CID_CHECK
1458 /* Definitions for module information */
1459 #define MAX_VID_LEN		8
1460 
1461 #ifdef	SUPPORT_MULTIPLE_BOARDTYPE
1462 #define MAX_BNAME_LEN		6
1463 
1464 typedef struct {
1465 	uint8 b_len;
1466 	unsigned char btype[MAX_VID_LEN];
1467 	char bname[MAX_BNAME_LEN];
1468 } board_info_t;
1469 
1470 #if defined(BCM4361_CHIP)
1471 board_info_t semco_PA_info[] = {
1472 	{ 3, { 0x0f, 0x08, }, { "_ePA" } },     /* semco All ePA */
1473 	{ 3, { 0x27, 0x08, }, { "_iPA" } },     /* semco 2g iPA, 5g ePA */
1474 	{ 3, { 0x1a, 0x08, }, { "_iPA" } },		/* semco 2g iPA, 5g ePA old */
1475 	{ 0, { 0x00, }, { "" } }   /* Default: Not specified yet */
1476 };
1477 #else
1478 board_info_t semco_board_info[] = {
1479 	{ 3, { 0x51, 0x07, }, { "_b90b" } },     /* semco three antenna */
1480 	{ 3, { 0x61, 0x07, }, { "_b90b" } },     /* semco two antenna */
1481 	{ 0, { 0x00, }, { "" } }   /* Default: Not specified yet */
1482 };
1483 board_info_t murata_board_info[] = {
1484 	{ 3, { 0xa5, 0x07, }, { "_b90" } },      /* murata three antenna */
1485 	{ 3, { 0xb0, 0x07, }, { "_b90b" } },     /* murata two antenna */
1486 	{ 3, { 0xb1, 0x07, }, { "_es5" } },     /* murata two antenna */
1487 	{ 0, { 0x00, }, { "" } }   /* Default: Not specified yet */
1488 };
1489 #endif /* BCM4361_CHIP */
1490 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
1491 
1492 typedef struct {
1493 	uint8 vid_length;
1494 	unsigned char vid[MAX_VID_LEN];
1495 	char cid_info[MAX_VNAME_LEN];
1496 } vid_info_t;
1497 
1498 #if defined(BCM4335_CHIP)
1499 vid_info_t vid_info[] = {
1500 	{ 3, { 0x33, 0x66, }, { "semcosh" } },		/* B0 Sharp 5G-FEM */
1501 	{ 3, { 0x33, 0x33, }, { "semco" } },		/* B0 Skyworks 5G-FEM and A0 chip */
1502 	{ 3, { 0x33, 0x88, }, { "semco3rd" } },		/* B0 Syri 5G-FEM */
1503 	{ 3, { 0x00, 0x11, }, { "muratafem1" } },	/* B0 ANADIGICS 5G-FEM */
1504 	{ 3, { 0x00, 0x22, }, { "muratafem2" } },	/* B0 TriQuint 5G-FEM */
1505 	{ 3, { 0x00, 0x33, }, { "muratafem3" } },	/* 3rd FEM: Reserved */
1506 	{ 0, { 0x00, }, { "murata" } }	/* Default: for Murata A0 module */
1507 };
1508 #elif defined(BCM4339_CHIP) || defined(BCM4354_CHIP) || \
1509 	defined(BCM4356_CHIP)
1510 vid_info_t vid_info[] = {			  /* 4339:2G FEM+5G FEM ,4354: 2G FEM+5G FEM */
1511 	{ 3, { 0x33, 0x33, }, { "semco" } },      /* 4339:Skyworks+sharp,4354:Panasonic+Panasonic */
1512 	{ 3, { 0x33, 0x66, }, { "semco" } },      /* 4339:  , 4354:Panasonic+SEMCO */
1513 	{ 3, { 0x33, 0x88, }, { "semco3rd" } },   /* 4339:  , 4354:SEMCO+SEMCO */
1514 	{ 3, { 0x90, 0x01, }, { "wisol" } },      /* 4339:  , 4354:Microsemi+Panasonic */
1515 	{ 3, { 0x90, 0x02, }, { "wisolfem1" } },  /* 4339:  , 4354:Panasonic+Panasonic */
1516 	{ 3, { 0x90, 0x03, }, { "wisolfem2" } },  /* 4354:Murata+Panasonic */
1517 	{ 3, { 0x00, 0x11, }, { "muratafem1" } }, /* 4339:  , 4354:Murata+Anadigics */
1518 	{ 3, { 0x00, 0x22, }, { "muratafem2"} },  /* 4339:  , 4354:Murata+Triquint */
1519 	{ 0, { 0x00, }, { "samsung" } }           /* Default: Not specified yet */
1520 };
1521 #elif defined(BCM4358_CHIP)
1522 vid_info_t vid_info[] = {
1523 	{ 3, { 0x33, 0x33, }, { "semco_b85" } },
1524 	{ 3, { 0x33, 0x66, }, { "semco_b85" } },
1525 	{ 3, { 0x33, 0x88, }, { "semco3rd_b85" } },
1526 	{ 3, { 0x90, 0x01, }, { "wisol_b85" } },
1527 	{ 3, { 0x90, 0x02, }, { "wisolfem1_b85" } },
1528 	{ 3, { 0x90, 0x03, }, { "wisolfem2_b85" } },
1529 	{ 3, { 0x31, 0x90, }, { "wisol_b85b" } },
1530 	{ 3, { 0x00, 0x11, }, { "murata_b85" } },
1531 	{ 3, { 0x00, 0x22, }, { "murata_b85"} },
1532 	{ 6, { 0x00, 0xFF, 0xFF, 0x00, 0x00, }, { "murata_b85"} },
1533 	{ 3, { 0x10, 0x33, }, { "semco_b85a" } },
1534 	{ 3, { 0x30, 0x33, }, { "semco_b85b" } },
1535 	{ 3, { 0x31, 0x33, }, { "semco_b85b" } },
1536 	{ 3, { 0x10, 0x22, }, { "murata_b85a" } },
1537 	{ 3, { 0x20, 0x22, }, { "murata_b85a" } },
1538 	{ 3, { 0x21, 0x22, }, { "murata_b85a" } },
1539 	{ 3, { 0x23, 0x22, }, { "murata_b85a" } },
1540 	{ 3, { 0x31, 0x22, }, { "murata_b85b" } },
1541 	{ 0, { 0x00, }, { "samsung" } }           /* Default: Not specified yet */
1542 };
1543 #elif defined(BCM4359_CHIP)
1544 vid_info_t vid_info[] = {
1545 #if defined(SUPPORT_BCM4359_MIXED_MODULES)
1546 	{ 3, { 0x34, 0x33, }, { "semco_b90b" } },
1547 	{ 3, { 0x40, 0x33, }, { "semco_b90b" } },
1548 	{ 3, { 0x41, 0x33, }, { "semco_b90b" } },
1549 	{ 3, { 0x11, 0x33, }, { "semco_b90b" } },
1550 	{ 3, { 0x33, 0x66, }, { "semco_b90b" } },
1551 	{ 3, { 0x23, 0x22, }, { "murata_b90b" } },
1552 	{ 3, { 0x40, 0x22, }, { "murata_b90b" } },
1553 	{ 3, { 0x10, 0x90, }, { "wisol_b90b" } },
1554 	{ 3, { 0x33, 0x33, }, { "semco_b90s_b1" } },
1555 	{ 3, { 0x66, 0x33, }, { "semco_b90s_c0" } },
1556 	{ 3, { 0x60, 0x22, }, { "murata_b90s_b1" } },
1557 	{ 3, { 0x61, 0x22, }, { "murata_b90s_b1" } },
1558 	{ 3, { 0x62, 0x22, }, { "murata_b90s_b1" } },
1559 	{ 3, { 0x63, 0x22, }, { "murata_b90s_b1" } },
1560 	{ 3, { 0x70, 0x22, }, { "murata_b90s_c0" } },
1561 	{ 3, { 0x71, 0x22, }, { "murata_b90s_c0" } },
1562 	{ 3, { 0x72, 0x22, }, { "murata_b90s_c0" } },
1563 	{ 3, { 0x73, 0x22, }, { "murata_b90s_c0" } },
1564 	{ 0, { 0x00, }, { "samsung" } }           /* Default: Not specified yet */
1565 #else /* SUPPORT_BCM4359_MIXED_MODULES */
1566 	{ 3, { 0x34, 0x33, }, { "semco" } },
1567 	{ 3, { 0x40, 0x33, }, { "semco" } },
1568 	{ 3, { 0x41, 0x33, }, { "semco" } },
1569 	{ 3, { 0x11, 0x33, }, { "semco" } },
1570 	{ 3, { 0x33, 0x66, }, { "semco" } },
1571 	{ 3, { 0x23, 0x22, }, { "murata" } },
1572 	{ 3, { 0x40, 0x22, }, { "murata" } },
1573 	{ 3, { 0x51, 0x22, }, { "murata" } },
1574 	{ 3, { 0x52, 0x22, }, { "murata" } },
1575 	{ 3, { 0x10, 0x90, }, { "wisol" } },
1576 	{ 0, { 0x00, }, { "samsung" } }           /* Default: Not specified yet */
1577 #endif /* SUPPORT_BCM4359_MIXED_MODULES */
1578 };
1579 #elif defined(BCM4361_CHIP)
1580 vid_info_t vid_info[] = {
1581 #if defined(SUPPORT_MIXED_MODULES)
1582 	{ 3, { 0x66, 0x33, }, { "semco_sky_r00a_e000_a0" } },
1583 	{ 3, { 0x30, 0x33, }, { "semco_sky_r01a_e30a_a1" } },
1584 	{ 3, { 0x31, 0x33, }, { "semco_sky_r02a_e30a_a1" } },
1585 	{ 3, { 0x32, 0x33, }, { "semco_sky_r02a_e30a_a1" } },
1586 	{ 3, { 0x51, 0x33, }, { "semco_sky_r01d_e31_b0" } },
1587 	{ 3, { 0x61, 0x33, }, { "semco_sem_r01f_e31_b0" } },
1588 	{ 3, { 0x62, 0x33, }, { "semco_sem_r02g_e31_b0" } },
1589 	{ 3, { 0x71, 0x33, }, { "semco_sky_r01h_e32_b0" } },
1590 	{ 3, { 0x81, 0x33, }, { "semco_sem_r01i_e32_b0" } },
1591 	{ 3, { 0x82, 0x33, }, { "semco_sem_r02j_e32_b0" } },
1592 	{ 3, { 0x91, 0x33, }, { "semco_sem_r02a_e32a_b2" } },
1593 	{ 3, { 0xa1, 0x33, }, { "semco_sem_r02b_e32a_b2" } },
1594 	{ 3, { 0x12, 0x22, }, { "murata_nxp_r012_1kl_a1" } },
1595 	{ 3, { 0x13, 0x22, }, { "murata_mur_r013_1kl_b0" } },
1596 	{ 3, { 0x14, 0x22, }, { "murata_mur_r014_1kl_b0" } },
1597 	{ 3, { 0x15, 0x22, }, { "murata_mur_r015_1kl_b0" } },
1598 	{ 3, { 0x20, 0x22, }, { "murata_mur_r020_1kl_b0" } },
1599 	{ 3, { 0x21, 0x22, }, { "murata_mur_r021_1kl_b0" } },
1600 	{ 3, { 0x22, 0x22, }, { "murata_mur_r022_1kl_b0" } },
1601 	{ 3, { 0x23, 0x22, }, { "murata_mur_r023_1kl_b0" } },
1602 	{ 3, { 0x24, 0x22, }, { "murata_mur_r024_1kl_b0" } },
1603 	{ 3, { 0x30, 0x22, }, { "murata_mur_r030_1kl_b0" } },
1604 	{ 3, { 0x31, 0x22, }, { "murata_mur_r031_1kl_b0" } },
1605 	{ 3, { 0x32, 0x22, }, { "murata_mur_r032_1kl_b0" } },
1606 	{ 3, { 0x33, 0x22, }, { "murata_mur_r033_1kl_b0" } },
1607 	{ 3, { 0x34, 0x22, }, { "murata_mur_r034_1kl_b0" } },
1608 	{ 3, { 0x50, 0x22, }, { "murata_mur_r020_1qw_b2" } },
1609 	{ 3, { 0x51, 0x22, }, { "murata_mur_r021_1qw_b2" } },
1610 	{ 3, { 0x52, 0x22, }, { "murata_mur_r022_1qw_b2" } },
1611 	{ 3, { 0x61, 0x22, }, { "murata_mur_r031_1qw_b2" } },
1612 	{ 0, { 0x00, }, { "samsung" } }           /* Default: Not specified yet */
1613 #endif /* SUPPORT_MIXED_MODULES */
1614 };
1615 #elif defined(BCM4375_CHIP)
1616 vid_info_t vid_info[] = {
1617 #if defined(SUPPORT_MIXED_MODULES)
1618 	{ 3, { 0x11, 0x33, }, { "semco_sky_e41_es11" } },
1619 	{ 3, { 0x33, 0x33, }, { "semco_sem_e43_es33" } },
1620 	{ 3, { 0x34, 0x33, }, { "semco_sem_e43_es34" } },
1621 	{ 3, { 0x35, 0x33, }, { "semco_sem_e43_es35" } },
1622 	{ 3, { 0x36, 0x33, }, { "semco_sem_e43_es36" } },
1623 	{ 3, { 0x41, 0x33, }, { "semco_sem_e43_cs41" } },
1624 	{ 3, { 0x51, 0x33, }, { "semco_sem_e43_cs51" } },
1625 	{ 3, { 0x53, 0x33, }, { "semco_sem_e43_cs53" } },
1626 	{ 3, { 0x61, 0x33, }, { "semco_sky_e43_cs61" } },
1627 	{ 3, { 0x10, 0x22, }, { "murata_mur_1rh_es10" } },
1628 	{ 3, { 0x11, 0x22, }, { "murata_mur_1rh_es11" } },
1629 	{ 3, { 0x12, 0x22, }, { "murata_mur_1rh_es12" } },
1630 	{ 3, { 0x13, 0x22, }, { "murata_mur_1rh_es13" } },
1631 	{ 3, { 0x20, 0x22, }, { "murata_mur_1rh_es20" } },
1632 	{ 3, { 0x32, 0x22, }, { "murata_mur_1rh_es32" } },
1633 	{ 3, { 0x41, 0x22, }, { "murata_mur_1rh_es41" } },
1634 	{ 3, { 0x42, 0x22, }, { "murata_mur_1rh_es42" } },
1635 	{ 3, { 0x43, 0x22, }, { "murata_mur_1rh_es43" } },
1636 	{ 3, { 0x44, 0x22, }, { "murata_mur_1rh_es44" } }
1637 #endif /* SUPPORT_MIXED_MODULES */
1638 };
1639 #elif defined(BCM4389_CHIP_DEF)
1640 vid_info_t vid_info[] = {
1641 #if defined(SUPPORT_MIXED_MODULES)
1642 	{ 3, { 0x21, 0x33, }, { "semco_sem_e53_es23" } },
1643 	{ 3, { 0x23, 0x33, }, { "semco_sem_e53_es23" } },
1644 	{ 3, { 0x24, 0x33, }, { "semco_sem_e53_es24" } },
1645 	{ 3, { 0x25, 0x33, }, { "semco_sem_e53_es25" } },
1646 	{ 3, { 0x31, 0x33, }, { "semco_sem_e53_es31" } },
1647 	{ 3, { 0x32, 0x33, }, { "semco_sem_e53_es32" } },
1648 	{ 3, { 0x40, 0x33, }, { "semco_sem_e53_es40" } },
1649 	{ 3, { 0x21, 0x22, }, { "murata_mur_1wk_es21" } },
1650 	{ 3, { 0x30, 0x22, }, { "murata_mur_1wk_es30" } },
1651 	{ 3, { 0x31, 0x22, }, { "murata_mur_1wk_es31" } },
1652 	{ 3, { 0x32, 0x22, }, { "murata_mur_1wk_es32" } },
1653 	{ 3, { 0x40, 0x22, }, { "murata_mur_1wk_es40" } },
1654 	{ 3, { 0x41, 0x22, }, { "murata_mur_1wk_es41" } },
1655 	{ 3, { 0x42, 0x22, }, { "murata_mur_1wk_es42" } },
1656 	{ 3, { 0x43, 0x22, }, { "murata_mur_1wk_es43" } },
1657 	{ 3, { 0x50, 0x22, }, { "murata_mur_1wk_es50" } }
1658 #endif /* SUPPORT_MIXED_MODULES */
1659 };
1660 #else
1661 vid_info_t vid_info[] = {
1662 	{ 0, { 0x00, }, { "samsung" } }			/* Default: Not specified yet */
1663 };
1664 #endif /* BCM_CHIP_ID */
1665 
1666 /* CID managment functions */
1667 
1668 char *
dhd_get_cid_info(unsigned char * vid,int vid_length)1669 dhd_get_cid_info(unsigned char *vid, int vid_length)
1670 {
1671 	int i;
1672 
1673 	for (i = 0; i < ARRAYSIZE(vid_info); i++) {
1674 		if (vid_info[i].vid_length-1 == vid_length &&
1675 				!memcmp(vid_info[i].vid, vid, vid_length)) {
1676 			return vid_info[i].cid_info;
1677 		}
1678 	}
1679 
1680 	DHD_ERROR(("%s : Can't find the cid info\n", __FUNCTION__));
1681 	return NULL;
1682 }
1683 
1684 int
dhd_check_module_cid(dhd_pub_t * dhdp)1685 dhd_check_module_cid(dhd_pub_t *dhdp)
1686 {
1687 	int ret = -1;
1688 #ifndef DHD_EXPORT_CNTL_FILE
1689 	const char *cidfilepath = CIDINFO;
1690 #endif /* DHD_EXPORT_CNTL_FILE */
1691 	int idx, max;
1692 	vid_info_t *cur_info;
1693 	unsigned char *tuple_start = NULL;
1694 	unsigned char tuple_length = 0;
1695 	unsigned char cid_info[MAX_VNAME_LEN];
1696 	int found = FALSE;
1697 #ifdef SUPPORT_MULTIPLE_BOARDTYPE
1698 	board_info_t *cur_b_info = NULL;
1699 	board_info_t *vendor_b_info = NULL;
1700 	unsigned char *btype_start;
1701 	unsigned char boardtype_len = 0;
1702 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
1703 
1704 	/* Try reading out from CIS */
1705 	if (!g_cis_buf) {
1706 		DHD_INFO(("%s: Couldn't read CIS info\n", __FUNCTION__));
1707 		return BCME_ERROR;
1708 	}
1709 
1710 	DHD_INFO(("%s: Reading CIS from local buffer\n", __FUNCTION__));
1711 #ifdef DUMP_CIS
1712 	dhd_dump_cis_buf(dhdp, DUMP_CIS_SIZE);
1713 #endif /* DUMP_CIS */
1714 
1715 	idx = dhd_find_tuple_idx_from_otp(dhdp, CIS_TUPLE_TAG_VENDOR, &tuple_length);
1716 	if (idx > 0) {
1717 		found = TRUE;
1718 		tuple_start = &g_cis_buf[idx];
1719 	}
1720 
1721 	if (found) {
1722 		max = sizeof(vid_info) / sizeof(vid_info_t);
1723 		for (idx = 0; idx < max; idx++) {
1724 			cur_info = &vid_info[idx];
1725 #ifdef BCM4358_CHIP
1726 			if (cur_info->vid_length  == 6 && tuple_length == 6) {
1727 				if (cur_info->vid[0] == tuple_start[0] &&
1728 					cur_info->vid[3] == tuple_start[3] &&
1729 					cur_info->vid[4] == tuple_start[4]) {
1730 					goto check_board_type;
1731 				}
1732 			}
1733 #endif /* BCM4358_CHIP */
1734 			if ((cur_info->vid_length == tuple_length) &&
1735 				(cur_info->vid_length != 0) &&
1736 				(memcmp(cur_info->vid, tuple_start,
1737 					cur_info->vid_length - 1) == 0)) {
1738 				goto check_board_type;
1739 			}
1740 		}
1741 	}
1742 
1743 	/* find default nvram, if exist */
1744 	DHD_ERROR(("%s: cannot find CIS TUPLE set as default\n", __FUNCTION__));
1745 	max = sizeof(vid_info) / sizeof(vid_info_t);
1746 	for (idx = 0; idx < max; idx++) {
1747 		cur_info = &vid_info[idx];
1748 		if (cur_info->vid_length == 0) {
1749 			goto write_cid;
1750 		}
1751 	}
1752 	DHD_ERROR(("%s: cannot find default CID\n", __FUNCTION__));
1753 	return BCME_ERROR;
1754 
1755 check_board_type:
1756 #ifdef SUPPORT_MULTIPLE_BOARDTYPE
1757 	idx = dhd_find_tuple_idx_from_otp(dhdp, CIS_TUPLE_TAG_BOARDTYPE, &tuple_length);
1758 	if (idx > 0) {
1759 		btype_start = &g_cis_buf[idx];
1760 		boardtype_len = tuple_length;
1761 		DHD_INFO(("%s: board type found.\n", __FUNCTION__));
1762 	} else {
1763 		boardtype_len = 0;
1764 	}
1765 #if defined(BCM4361_CHIP)
1766 	vendor_b_info = semco_PA_info;
1767 	max = sizeof(semco_PA_info) / sizeof(board_info_t);
1768 #else
1769 	if (strcmp(cur_info->cid_info, "semco") == 0) {
1770 		vendor_b_info = semco_board_info;
1771 		max = sizeof(semco_board_info) / sizeof(board_info_t);
1772 	} else if (strcmp(cur_info->cid_info, "murata") == 0) {
1773 		vendor_b_info = murata_board_info;
1774 		max = sizeof(murata_board_info) / sizeof(board_info_t);
1775 	} else {
1776 		max = 0;
1777 	}
1778 #endif /* BCM4361_CHIP */
1779 	if (boardtype_len) {
1780 		for (idx = 0; idx < max; idx++) {
1781 			cur_b_info = vendor_b_info;
1782 			if ((cur_b_info->b_len == boardtype_len) &&
1783 				(cur_b_info->b_len != 0) &&
1784 				(memcmp(cur_b_info->btype, btype_start,
1785 					cur_b_info->b_len - 1) == 0)) {
1786 				DHD_INFO(("%s : board type name : %s\n",
1787 					__FUNCTION__, cur_b_info->bname));
1788 				break;
1789 			}
1790 			cur_b_info = NULL;
1791 			vendor_b_info++;
1792 		}
1793 	}
1794 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
1795 
1796 write_cid:
1797 #ifdef SUPPORT_MULTIPLE_BOARDTYPE
1798 	if (cur_b_info && cur_b_info->b_len > 0) {
1799 		strcpy(cid_info, cur_info->cid_info);
1800 		strcpy(cid_info + strlen(cur_info->cid_info), cur_b_info->bname);
1801 	} else
1802 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
1803 		strcpy(cid_info, cur_info->cid_info);
1804 
1805 	DHD_INFO(("%s: CIS MATCH FOUND : %s\n", __FUNCTION__, cid_info));
1806 #ifndef DHD_EXPORT_CNTL_FILE
1807 	dhd_write_file(cidfilepath, cid_info, strlen(cid_info) + 1);
1808 #else
1809 	strlcpy(cidinfostr, cid_info, MAX_VNAME_LEN);
1810 #endif /* DHD_EXPORT_CNTL_FILE */
1811 
1812 	return ret;
1813 }
1814 
1815 #ifdef SUPPORT_MULTIPLE_MODULE_CIS
1816 #ifndef DHD_EXPORT_CNTL_FILE
1817 static bool
dhd_check_module(char * module_name)1818 dhd_check_module(char *module_name)
1819 {
1820 	char vname[MAX_VNAME_LEN];
1821 	const char *cidfilepath = CIDINFO;
1822 	int ret;
1823 
1824 	memset(vname, 0, sizeof(vname));
1825 	ret = dhd_read_file(cidfilepath, vname, sizeof(vname) - 1);
1826 	if (ret < 0) {
1827 		return FALSE;
1828 	}
1829 	DHD_INFO(("%s: This module is %s \n", __FUNCTION__, vname));
1830 	return strstr(vname, module_name) ? TRUE : FALSE;
1831 }
1832 #else
1833 bool
dhd_check_module(char * module_name)1834 dhd_check_module(char *module_name)
1835 {
1836 	return strstr(cidinfostr, module_name) ? TRUE : FALSE;
1837 }
1838 #endif /* !DHD_EXPORT_CNTL_FILE */
1839 
1840 int
dhd_check_module_b85a(void)1841 dhd_check_module_b85a(void)
1842 {
1843 	int ret;
1844 	char *vname_b85a = "_b85a";
1845 
1846 	if (dhd_check_module(vname_b85a)) {
1847 		DHD_INFO(("%s: It's a b85a module\n", __FUNCTION__));
1848 		ret = 1;
1849 	} else {
1850 		DHD_INFO(("%s: It is not a b85a module\n", __FUNCTION__));
1851 		ret = -1;
1852 	}
1853 
1854 	return ret;
1855 }
1856 
1857 int
dhd_check_module_b90(void)1858 dhd_check_module_b90(void)
1859 {
1860 	int ret = 0;
1861 	char *vname_b90b = "_b90b";
1862 	char *vname_b90s = "_b90s";
1863 
1864 	if (dhd_check_module(vname_b90b)) {
1865 		DHD_INFO(("%s: It's a b90b module \n", __FUNCTION__));
1866 		ret = BCM4359_MODULE_TYPE_B90B;
1867 	} else if (dhd_check_module(vname_b90s)) {
1868 		DHD_INFO(("%s: It's a b90s module\n", __FUNCTION__));
1869 		ret = BCM4359_MODULE_TYPE_B90S;
1870 	} else {
1871 		DHD_ERROR(("%s: It's neither b90b nor b90s\n", __FUNCTION__));
1872 		ret = BCME_ERROR;
1873 	}
1874 
1875 	return ret;
1876 }
1877 #endif /* SUPPORT_MULTIPLE_MODULE_CIS */
1878 
1879 #define CID_FEM_MURATA	"_mur_"
1880 /* extract module type from cid information */
1881 /* XXX: extract string by delimiter '_' at specific counting position.
1882  * it would be used for module type information.
1883  * for example, cid information is 'semco_sky_r02a_e30a_a1',
1884  * then output (module type) is 'r02a_e30a_a1' when index is 3.
1885  */
1886 int
dhd_check_module_bcm(char * module_type,int index,bool * is_murata_fem)1887 dhd_check_module_bcm(char *module_type, int index, bool *is_murata_fem)
1888 {
1889 	int ret = 0, i;
1890 	char vname[MAX_VNAME_LEN];
1891 	char *ptr = NULL;
1892 #ifndef DHD_EXPORT_CNTL_FILE
1893 	const char *cidfilepath = CIDINFO;
1894 #endif /* DHD_EXPORT_CNTL_FILE */
1895 
1896 	memset(vname, 0, sizeof(vname));
1897 
1898 #ifndef DHD_EXPORT_CNTL_FILE
1899 	ret = dhd_read_file(cidfilepath, vname, sizeof(vname) - 1);
1900 	if (ret < 0) {
1901 		DHD_ERROR(("%s: failed to get module infomaion from .cid.info\n",
1902 			__FUNCTION__));
1903 		return ret;
1904 	}
1905 #else
1906 	strlcpy(vname, cidinfostr, MAX_VNAME_LEN);
1907 #endif /* DHD_EXPORT_CNTL_FILE */
1908 
1909 	for (i = 1, ptr = vname; i < index && ptr; i++) {
1910 		ptr = bcmstrstr(ptr, "_");
1911 		if (ptr) {
1912 			ptr++;
1913 		}
1914 	}
1915 
1916 	if (bcmstrnstr(vname, MAX_VNAME_LEN, CID_FEM_MURATA, 5)) {
1917 		*is_murata_fem = TRUE;
1918 	}
1919 
1920 	if (ptr) {
1921 		memcpy(module_type, ptr, strlen(ptr));
1922 	} else {
1923 		DHD_ERROR(("%s: failed to get module infomaion\n", __FUNCTION__));
1924 		return BCME_ERROR;
1925 	}
1926 
1927 	DHD_INFO(("%s: module type = %s \n", __FUNCTION__, module_type));
1928 
1929 	return ret;
1930 }
1931 #endif /* USE_CID_CHECK */
1932 
1933 #ifdef USE_DIRECT_VID_TAG
1934 int
dhd_check_module_cid(dhd_pub_t * dhdp)1935 dhd_check_module_cid(dhd_pub_t *dhdp)
1936 {
1937 	int ret = BCME_ERROR;
1938 	int idx;
1939 	unsigned char tuple_length = 0;
1940 	unsigned char *vid = NULL;
1941 	unsigned char cid_info[MAX_VNAME_LEN];
1942 #ifndef DHD_EXPORT_CNTL_FILE
1943 	const char *cidfilepath = CIDINFO;
1944 #endif /* DHD_EXPORT_CNTL_FILE */
1945 
1946 	/* Try reading out from CIS */
1947 	if (!g_cis_buf) {
1948 		DHD_INFO(("%s: Couldn't read CIS info\n", __FUNCTION__));
1949 		return BCME_ERROR;
1950 	}
1951 
1952 	DHD_INFO(("%s: Reading CIS from local buffer\n", __FUNCTION__));
1953 #ifdef DUMP_CIS
1954 	dhd_dump_cis_buf(dhdp, DUMP_CIS_SIZE);
1955 #endif /* DUMP_CIS */
1956 	idx = dhd_find_tuple_idx_from_otp(dhdp, CIS_TUPLE_TAG_VENDOR, &tuple_length);
1957 	if (idx > 0) {
1958 		vid = &g_cis_buf[idx];
1959 		DHD_INFO(("%s: VID FOUND : 0x%x%x\n", __FUNCTION__,
1960 			vid[VENDOR_OFF], vid[MD_REV_OFF]));
1961 	} else {
1962 		DHD_ERROR(("%s: use nvram default\n", __FUNCTION__));
1963 		return BCME_ERROR;
1964 	}
1965 
1966 	memset(cid_info, 0, sizeof(MAX_VNAME_LEN));
1967 	cid_info[MD_REV_OFF] = vid[MD_REV_OFF];
1968 	cid_info[VENDOR_OFF] = vid[VENDOR_OFF];
1969 #ifndef DHD_EXPORT_CNTL_FILE
1970 	dhd_write_file(cidfilepath, cid_info, strlen(cid_info) + 1);
1971 #else
1972 	strlcpy(cidinfostr, cid_info, MAX_VNAME_LEN);
1973 #endif /* DHD_EXPORT_CNTL_FILE */
1974 
1975 	DHD_INFO(("%s: cidinfostr %x%x\n", __FUNCTION__,
1976 			cidinfostr[VENDOR_OFF], cidinfostr[MD_REV_OFF]));
1977 	return ret;
1978 }
1979 
1980 int
dhd_check_stored_module_info(char * vid)1981 dhd_check_stored_module_info(char *vid)
1982 {
1983 	int ret = BCME_OK;
1984 #ifndef DHD_EXPORT_CNTL_FILE
1985 	const char *cidfilepath = CIDINFO;
1986 #endif /* DHD_EXPORT_CNTL_FILE */
1987 
1988 	memset(vid, 0, MAX_VID_LEN);
1989 
1990 #ifndef DHD_EXPORT_CNTL_FILE
1991 	ret = dhd_read_file(cidfilepath, vid, MAX_VID_LEN - 1);
1992 	if (ret != BCME_OK) {
1993 		DHD_ERROR(("%s: failed to get module infomaion from .cid.info\n",
1994 			__FUNCTION__));
1995 		return ret;
1996 	}
1997 #else
1998 	strlcpy(vid, cidinfostr, MAX_VID_LEN);
1999 #endif /* DHD_EXPORT_CNTL_FILE */
2000 
2001 	if (vid[0] == (char)0) {
2002 		DHD_ERROR(("%s : Failed to get module information \n", __FUNCTION__));
2003 		return BCME_ERROR;
2004 	}
2005 
2006 	DHD_INFO(("%s: stored VID= 0x%x%x\n", __FUNCTION__, vid[VENDOR_OFF], vid[MD_REV_OFF]));
2007 	return ret;
2008 }
2009 #endif /* USE_DIRECT_VID_TAG */
2010 #endif /* DHD_USE_CISINFO */
2011