wifi: update ap6356 driver to bcmdhd.101.10.361.x [1/1]
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.101.10.361.x / dhd_custom_cis.c
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
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
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 *
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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*
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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 */