2 * Process CIS information from OTP for customer platform
3 * (Handle the MAC address and module information)
5 * Copyright (C) 2020, Broadcom.
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:
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.
22 * <<Broadcom-WL-IPTag/Open:>>
32 #include <dngl_stats.h>
36 #include <dhd_linux.h>
39 #include <linux/fcntl.h>
41 #include <linux/list.h>
44 #ifdef DHD_USE_CISINFO_FROM_OTP
45 #include <bcmdevs_legacy.h> /* need to still support chips no longer in trunk firmware */
47 #include <pcie_core.h>
49 #endif /* DHD_USE_CISINFO_FROM_OTP */
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
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
70 typedef struct cis_tuple_format
{
72 uint8 len
; /* total length of tag and data */
78 read_otp_from_bp(dhd_bus_t
*bus
, uint32
*data_buf
)
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 */
85 int boardtype_backplane_data
[] = {
87 0x0e4fffff /* Keep on ARMHTAVAIL */
90 uint32 cis_start_addr
= CIS_TUPLE_START_ADDRESS
;
91 uint32 org_boardtype_backplane_data
[] = {
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"));
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"));
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"));
117 DHD_INFO(("%s: boardtype_backplane_addr 0x%08x rdata 0x%04x\n",
118 __FUNCTION__
, boardtype_backplane_addr
[bp_idx
], int_val
));
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
) {
127 DHD_INFO(("%s: tuple index %d, raw data 0x%08x\n", __FUNCTION__
, i
, data_buf
[i
]));
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"));
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"));
144 DHD_INFO(("%s: boardtype_backplane_addr 0x%08x rdata 0x%04x\n",
145 __FUNCTION__
, boardtype_backplane_addr
[bp_idx
], int_val
));
148 return i
* sizeof(uint32
);
152 dhd_parse_board_information_bcm(dhd_bus_t
*bus
, int *boardtype
,
153 unsigned char *vid
, int *vid_length
)
156 uint32 raw_data
[CIS_TUPLE_MAX_COUNT
];
157 cis_tuple_format_t
*tuple
;
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__
));
165 tuple
= (cis_tuple_format_t
*)raw_data
;
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__
));
173 *vid_length
= *boardtype
= 0;
175 /* find tagged parameter */
176 while ((totlen
>= (tuple
->len
+ CIS_TUPLE_HDR_LEN
)) &&
177 (*vid_length
== 0 || *boardtype
== 0)) {
180 if ((tuple
->tag
== CIS_TUPLE_TAG_VENDOR
) &&
181 (totlen
>= (int)(len
+ CIS_TUPLE_HDR_LEN
))) {
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
);
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
);
194 tuple
= (cis_tuple_format_t
*)((uint8
*)tuple
+ (len
+ CIS_TUPLE_HDR_LEN
));
195 totlen
-= (len
+ CIS_TUPLE_HDR_LEN
);
198 if (*vid_length
<= 0 || *boardtype
<= 0) {
199 DHD_ERROR(("failed to parse information (vid=%d, boardtype=%d)\n",
200 *vid_length
, *boardtype
));
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"
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"} }
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"} }
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"} }
300 /* select the NVRAM/FW tag naming table */
302 select_naming_table(dhd_pub_t
*dhdp
, int *table_size
)
304 naming_info_t
* info
= NULL
;
306 if (!dhdp
|| !dhdp
->bus
|| !dhdp
->bus
->sih
)
308 DHD_ERROR(("%s : Invalid pointer \n", __FUNCTION__
));
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
));
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
));
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
));
330 DHD_ERROR(("%s: No MODULE NAMING TABLE found\n", __FUNCTION__
));
337 #define CID_FEM_MURATA "_mur_"
339 dhd_find_naming_info(dhd_pub_t
*dhdp
, char *module_type
)
342 naming_info_t
*info
= NULL
;
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__
));
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
))) {
364 static naming_info_t
*
365 dhd_find_naming_info_by_cid(dhd_pub_t
*dhdp
, char *cid_info
)
369 naming_info_t
*info
= NULL
;
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__
));
378 /* truncate extension */
379 for (i
= 1, ptr
= cid_info
; i
< MODULE_NAME_INDEX_MAX
&& ptr
; i
++) {
380 ptr
= bcmstrstr(ptr
, "_");
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
))) {
398 dhd_find_naming_info_by_chip_rev(dhd_pub_t
*dhdp
, bool *is_murata_fem
)
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
;
407 DHD_ERROR(("%s: dhdp is NULL \n", __FUNCTION__
));
413 if (!bus
|| !bus
->sih
) {
414 DHD_ERROR(("%s:bus(%p) or bus->sih is NULL\n", __FUNCTION__
, bus
));
418 chip_rev
= bus
->sih
->chiprev
;
420 if (dhd_parse_board_information_bcm(bus
, &board_type
, vid
, &vid_length
)
422 DHD_ERROR(("%s:failed to parse board information\n", __FUNCTION__
));
426 DHD_INFO(("%s:chip version %d\n", __FUNCTION__
, chip_rev
));
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
);
438 #endif /* BCM4361_CHIP */
440 cid_info
= dhd_get_cid_info(vid
, vid_length
);
442 info
= dhd_find_naming_info_by_cid(dhdp
, cid_info
);
443 if (strstr(cid_info
, CID_FEM_MURATA
)) {
444 *is_murata_fem
= TRUE
;
451 #endif /* USE_CID_CHECK */
452 #ifdef USE_DIRECT_VID_TAG
454 concate_nvram_by_vid(dhd_pub_t
*dhdp
, char *nv_path
, char *chipstr
)
456 unsigned char vid
[MAX_VID_LEN
];
457 unsigned char vid2str
[MAX_VID_LEN
];
459 memset(vid
, 0, sizeof(vid
));
460 memset(vid2str
, 0, sizeof(vid2str
));
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
));
470 int board_type
= 0, vid_length
= 0;
471 dhd_bus_t
*bus
= NULL
;
474 DHD_ERROR(("%s : dhdp is NULL \n", __FUNCTION__
));
478 if (dhd_parse_board_information_bcm(bus
, &board_type
, vid
, &vid_length
)
480 DHD_ERROR(("%s:failed to parse board information\n", __FUNCTION__
));
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
));
495 #endif /* USE_DIRECT_VID_TAG */
496 #endif /* DHD_USE_CISINFO_FROM_OTP */
498 #ifdef DHD_USE_CISINFO
500 /* File Location to keep each information */
502 #define MACINFO PLATFORM_PATH".mac.info"
503 #define CIDINFO PLATFORM_PATH".cid.info"
505 #define MACINFO_EFS "/csa/.mac.info"
507 #define MACINFO_EFS "/efs/wifi/.mac.info"
508 #define CIDINFO_DATA "/data/.cid.info"
509 #endif /* PLATFORM_SLP */
511 #define MACINFO "/opt/.mac.info"
512 #define MACINFO_EFS "/opt/.efs.mac.info"
513 #define CIDINFO "/opt/.cid.info"
514 #endif /* OEM_ANDROID */
516 /* Definitions for MAC address */
517 #define MAC_BUF_SIZE 20
518 #define MAC_CUSTOM_FORMAT "%02X:%02X:%02X:%02X:%02X:%02X"
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
525 #define CIS_BUF_SIZE 512
526 #endif /* BCM4359_CHIP */
528 #define DUMP_CIS_SIZE 48
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
538 #ifdef CONFIG_BCMDHD_PCIE
539 #if defined(BCM4361_CHIP) || defined(BCM4375_CHIP)
540 #define OTP_OFFSET 208
541 #elif defined(BCM4389_CHIP_DEF)
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 */
550 unsigned char *g_cis_buf
= NULL
;
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 */
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 */
566 /* otp region read/write information */
567 typedef struct otp_rgn_rw_info
{
576 /* otp region status information */
577 typedef struct otp_rgn_stat_info
{
581 } otp_rgn_stat_info_t
;
583 typedef int (pack_handler_t
)(void *ctx
, uint8
*buf
, uint16
*buflen
);
585 /* Common Interface Functions */
587 dhd_alloc_cis(dhd_pub_t
*dhdp
)
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__
));
595 DHD_ERROR(("%s: Local CIS buffer is alloced\n", __FUNCTION__
));
596 memset(g_cis_buf
, 0, CIS_BUF_SIZE
);
603 dhd_clear_cis(dhd_pub_t
*dhdp
)
606 MFREE(dhdp
->osh
, g_cis_buf
, CIS_BUF_SIZE
);
608 DHD_ERROR(("%s: Local CIS buffer is freed\n", __FUNCTION__
));
612 #ifdef DHD_READ_CIS_FROM_BP
614 dhd_read_cis(dhd_pub_t
*dhdp
)
616 int ret
= 0, totlen
= 0;
617 uint32 raw_data
[CIS_TUPLE_MAX_COUNT
];
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 */
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__
));
631 (void)memcpy_s(g_cis_buf
+ cis_offset
, CIS_BUF_SIZE
, raw_data
, totlen
);
636 dhd_read_cis(dhd_pub_t
*dhdp
)
640 int buf_size
= CIS_BUF_SIZE
;
641 int length
= strlen("cisdump");
643 if (length
>= buf_size
) {
644 DHD_ERROR(("%s: check CIS_BUF_SIZE\n", __FUNCTION__
));
648 /* Try reading out from CIS */
649 cish
= (cis_rw_t
*)(g_cis_buf
+ 8);
652 cish
->nbytes
= buf_size
;
653 strlcpy(g_cis_buf
, "cisdump", buf_size
);
655 ret
= dhd_wl_ioctl_cmd(dhdp
, WLC_GET_VAR
, g_cis_buf
, buf_size
, 0, 0);
657 if (ret
== BCME_UNSUPPORTED
) {
658 DHD_ERROR(("%s: get cisdump, UNSUPPORTED\n", __FUNCTION__
));
660 DHD_ERROR(("%s : get cisdump err(%d)\n",
669 #endif /* DHD_READ_CIS_FROM_BP */
672 dhd_otp_process_iov_resp_buf(void *ctx
, void *iov_resp
, uint16 cmd_id
,
673 bcm_xtlv_unpack_cbfn_t cbfn
)
675 bcm_iov_buf_t
*p_resp
= NULL
;
679 /* check for version */
680 version
= dtoh16(*(uint16
*)iov_resp
);
681 if (version
!= WL_OTP_IOV_VERSION
) {
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
);
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
)
698 bcm_iov_buf_t
*iov_buf
= NULL
;
699 uint8
*iov_resp
= NULL
;
701 int buf_size
= CIS_BUF_SIZE
;
702 uint16 iovlen
= 0, buflen
= 0, buflen_start
= 0;
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__
));
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__
));
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
) {
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
;
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
);
738 DHD_ERROR(("%s: Failed to get otp iovar\n", __FUNCTION__
));
743 MFREE(dhdp
->osh
, iov_buf
, WLC_IOCTL_SMLEN
);
746 MFREE(dhdp
->osh
, iov_resp
, buf_size
);
756 dhd_otp_cbfn_rgnstatus(void *ctx
, const uint8
*data
, uint16 type
, uint16 len
)
758 otp_rgn_stat_info_t
*stat_info
= (otp_rgn_stat_info_t
*)ctx
;
763 DHD_ERROR(("%s: bad argument !!!\n", __FUNCTION__
));
768 case WL_OTP_XTLV_RGN
:
769 stat_info
->rgnid
= *data
;
771 case WL_OTP_XTLV_ADDR
:
772 stat_info
->rgnstart
= dtoh16((uint16
)*data
);
774 case WL_OTP_XTLV_SIZE
:
775 stat_info
->rgnsize
= dtoh16((uint16
)*data
);
778 DHD_ERROR(("%s: unknown tlv %u\n", __FUNCTION__
, type
));
786 dhd_otp_packfn_rgnstatus(void *ctx
, uint8
*buf
, uint16
*buflen
)
790 uint16 len
= *buflen
;
791 uint8 rgnid
= OTP_RGN_SW
;
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
));
808 dhd_otp_packfn_rgndump(void *ctx
, uint8
*buf
, uint16
*buflen
)
812 uint16 len
= *buflen
, size
= WLC_IOCTL_MAXLEN
;
813 uint8 rgnid
= OTP_RGN_SW
;
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
));
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
));
836 dhd_otp_cbfn_rgndump(void *ctx
, const uint8
*data
, uint16 type
, uint16 len
)
838 otp_rgn_rw_info_t
*rw_info
= (otp_rgn_rw_info_t
*)ctx
;
843 DHD_ERROR(("%s: bad argument !!!\n", __FUNCTION__
));
848 case WL_OTP_XTLV_RGN
:
849 rw_info
->rgnid
= *data
;
851 case WL_OTP_XTLV_DATA
:
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
856 (void)memcpy_s(&rw_info
->data
, sizeof(rw_info
->data
),
857 &data
, sizeof(rw_info
->data
));
858 rw_info
->datasize
= len
;
861 DHD_ERROR(("%s: unknown tlv %u\n", __FUNCTION__
, type
));
868 dhd_read_otp_sw_rgn(dhd_pub_t
*dhdp
)
871 otp_rgn_rw_info_t rw_info
;
872 otp_rgn_stat_info_t stat_info
;
874 memset(&rw_info
, 0, sizeof(rw_info
));
875 memset(&stat_info
, 0, sizeof(stat_info
));
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
));
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
));
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
));
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
)
905 tuple_entry_t
*entry
;
907 entry
= MALLOCZ(dhdp
->osh
, sizeof(tuple_entry_t
));
909 DHD_ERROR(("%s: failed to alloc entry\n", __FUNCTION__
));
913 entry
->cis_idx
= idx
;
919 dhd_free_tuple_entry(dhd_pub_t
*dhdp
, struct list_head
*head
)
921 tuple_entry_t
*entry
;
923 while (!list_empty(head
)) {
924 entry
= list_entry(head
->next
, tuple_entry_t
, list
);
925 list_del(&entry
->list
);
927 MFREE(dhdp
->osh
, entry
, sizeof(tuple_entry_t
));
932 dhd_find_tuple_list_from_otp(dhd_pub_t
*dhdp
, int req_tup
,
933 unsigned char* req_tup_len
, struct list_head
*head
)
935 int idx
= OTP_OFFSET
+ sizeof(cis_rw_t
);
936 int tup
, tup_len
= 0;
937 int buf_len
= CIS_BUF_SIZE
;
940 #if defined(BCM4389_CHIP_DEF)
941 /* override OTP_OFFEST for 4389 */
943 #endif /* BCM4389_CHIP_DEF */
946 DHD_ERROR(("%s: Couldn't find cis info from"
947 " local buffer\n", __FUNCTION__
));
952 tup
= g_cis_buf
[idx
++];
953 if (tup
== CIS_TUPLE_NULL
|| tup
== CIS_DUMP_END
) {
956 tup_len
= g_cis_buf
[idx
++];
957 if ((idx
+ tup_len
) > buf_len
) {
961 if (tup
== CIS_TUPLE_TAG_START
&&
962 tup_len
!= CIS_TUPLE_NULL
&&
963 g_cis_buf
[idx
] == req_tup
) {
966 tuple_entry_t
*entry
;
967 entry
= dhd_alloc_tuple_entry(dhdp
, idx
);
969 list_add_tail(&entry
->list
, head
);
973 if (found
== 1 && req_tup_len
) {
974 *req_tup_len
= tup_len
;
980 } while (tup
!= CIS_DUMP_END
&& (idx
< buf_len
));
982 return (found
> 0) ? found
: BCME_ERROR
;
984 #endif /* GET_MAC_FROM_OTP || USE_CID_CHECK */
988 dhd_dump_cis_buf(dhd_pub_t
*dhdp
, int size
)
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 */
1003 if (size
> CIS_BUF_SIZE
) {
1004 size
= CIS_BUF_SIZE
;
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) {
1014 if ((i
% 16) != 15) {
1017 DHD_ERROR(("========== END CIS DUMP ==========\n"));
1019 #endif /* DUMP_CIS */
1021 /* MAC address mangement functions */
1024 dhd_create_random_mac(char *buf
, unsigned int buf_len
)
1028 memset(random_mac
, 0, sizeof(random_mac
));
1029 get_random_bytes(random_mac
, 3);
1031 snprintf(buf
, buf_len
, MAC_CUSTOM_FORMAT
, 0x00, 0x12, 0x34,
1032 (uint32
)random_mac
[0], (uint32
)random_mac
[1], (uint32
)random_mac
[2]);
1034 DHD_ERROR(("%s: The Random Generated MAC ID: %s\n",
1035 __FUNCTION__
, random_mac
));
1038 #ifndef DHD_MAC_ADDR_EXPORT
1040 dhd_set_macaddr_from_file(dhd_pub_t
*dhdp
)
1042 char mac_buf
[MAC_BUF_SIZE
];
1043 char *filepath_efs
= MACINFO_EFS
;
1045 char *filepath_mac
= MACINFO
;
1046 #endif /* PLATFORM_SLP */
1048 struct dhd_info
*dhd
;
1049 struct ether_addr
*mac
;
1050 char *invalid_mac
= "00:00:00:00:00:00";
1056 DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__
));
1060 memset(mac_buf
, 0, sizeof(mac_buf
));
1062 /* Read MAC address from the specified file */
1063 ret
= dhd_read_file(filepath_efs
, mac_buf
, sizeof(mac_buf
) - 1);
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
));
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
));
1076 DHD_ERROR(("%s: MAC address [%s] written into File: %s\n",
1077 __FUNCTION__
, mac_buf
, filepath_efs
));
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
));
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
));
1091 #endif /* PLATFORM_SLP */
1093 mac_buf
[sizeof(mac_buf
) - 1] = '\0';
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]));
1101 if (_dhd_set_mac_address(dhd
, 0, mac
) == 0) {
1102 DHD_INFO(("%s: MAC Address is overwritten\n", __FUNCTION__
));
1104 DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__
));
1111 dhd_set_macaddr_from_file(dhd_pub_t
*dhdp
)
1113 char mac_buf
[MAC_BUF_SIZE
];
1115 struct dhd_info
*dhd
;
1116 struct ether_addr
*mac
;
1122 DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__
));
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__
));
1136 /* Write the MAC address to the Dongle */
1137 memcpy(mac
, &sysfs_mac_addr
, sizeof(sysfs_mac_addr
));
1139 if (_dhd_set_mac_address(dhd
, 0, mac
) == 0) {
1140 DHD_INFO(("%s: MAC Address is overwritten\n", __FUNCTION__
));
1142 DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__
));
1147 #endif /* !DHD_MAC_ADDR_EXPORT */
1148 #endif /* READ_MACADDR */
1150 #ifdef GET_MAC_FROM_OTP
1152 dhd_set_default_macaddr(dhd_pub_t
*dhdp
)
1154 char iovbuf
[WLC_IOCTL_SMLEN
];
1155 struct ether_addr
*mac
;
1159 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__
));
1165 /* Read the default MAC address */
1166 ret
= dhd_iovar(dhdp
, 0, "cur_etheraddr", NULL
, 0, iovbuf
, sizeof(iovbuf
),
1169 DHD_ERROR(("%s: Can't get the default MAC address\n", __FUNCTION__
));
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 */
1183 dhd_verify_macaddr(dhd_pub_t
*dhdp
, struct list_head
*head
)
1185 tuple_entry_t
*cur
, *next
;
1186 int idx
= -1; /* Invalid index */
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
));
1195 if (!memcmp(&g_cis_buf
[cur
->cis_idx
],
1196 &g_cis_buf
[next
->cis_idx
], ETHER_ADDR_LEN
)) {
1207 dhd_check_module_mac(dhd_pub_t
*dhdp
)
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
;
1217 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__
));
1223 DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__
));
1227 #if defined(DHD_READ_CIS_FROM_BP) && defined(READ_MACADDR)
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
1233 if (dhd_bus_get_fw_mode(dhdp
) == DHD_FLAG_STA_MODE
) {
1234 dhd_clear_cis(dhdp
);
1236 #endif /* DHD_READ_CIS_FROM_BP && READ_MACADDR */
1239 memset(otp_mac_buf
, 0, sizeof(otp_mac_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__
));
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) {
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) {
1264 DHD_INFO(("%s: Couldn't read CIS information\n", __FUNCTION__
));
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) {
1274 /* sysfs mac addr is confirmed with valid format in set_mac_addr */
1275 memcpy(mac
, &sysfs_mac_addr
, sizeof(sysfs_mac_addr
));
1277 #endif /* !DHD_MAC_ADDR_EXPORT */
1279 struct list_head mac_list
;
1280 unsigned char tuple_len
= 0;
1282 int idx
= -1; /* Invalid index */
1285 dhd_dump_cis_buf(dhdp
, DUMP_CIS_SIZE
);
1286 #endif /* DUMP_CIS */
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
) {
1294 tuple_entry_t
*cur
= list_entry((&mac_list
)->next
,
1295 tuple_entry_t
, list
);
1298 /* Find the start index of MAC address */
1299 idx
= dhd_verify_macaddr(dhdp
, &mac_list
);
1303 /* Find the MAC address */
1305 #ifdef DHD_EXPORT_CNTL_FILE
1307 * WAR for incorrect otp mac address (including multicast bit)
1308 * for SEMCo e53_es31 module
1310 if (strcmp(cidinfostr
, "semco_sem_e53_es31") == 0) {
1311 g_cis_buf
[idx
] &= 0xFE;
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
])));
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
);
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
)));
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
));
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) {
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
));
1351 #endif /* !DHD_MAC_ADDR_EXPORT */
1354 if (_dhd_set_mac_address(dhd
, 0, mac
) == 0) {
1355 DHD_INFO(("%s: MAC Address is set\n", __FUNCTION__
));
1357 DHD_ERROR(("%s: Failed to set MAC address\n", __FUNCTION__
));
1362 #endif /* GET_MAC_FROM_OTP */
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
1369 #ifndef DHD_MAC_ADDR_EXPORT
1370 #ifdef WRITE_MACADDR
1372 dhd_write_macaddr(struct ether_addr
*mac
)
1374 char *filepath_data
= MACINFO
;
1375 char *filepath_efs
= MACINFO_EFS
;
1376 char mac_buf
[MAC_BUF_SIZE
];
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]);
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
));
1396 DHD_ERROR(("%s: MAC address [%s] Failed to write into"
1397 " File: %s\n", __FUNCTION__
, mac_buf
, filepath_data
));
1401 DHD_ERROR(("%s: filepath_data doesn't exist\n", __FUNCTION__
));
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
));
1414 DHD_ERROR(("%s: MAC address [%s] Failed to write into"
1415 " File: %s\n", __FUNCTION__
, mac_buf
, filepath_efs
));
1419 DHD_ERROR(("%s: filepath_efs doesn't exist\n", __FUNCTION__
));
1424 #endif /* WRITE_MACADDR */
1425 #endif /* !DHD_MAC_ADDR_EXPORT */
1427 #if defined(USE_CID_CHECK) || defined(USE_DIRECT_VID_TAG)
1429 dhd_find_tuple_idx_from_otp(dhd_pub_t
*dhdp
, int req_tup
, unsigned char *req_tup_len
)
1431 struct list_head head
;
1436 DHD_ERROR(("%s: Couldn't find cis info from"
1437 " local buffer\n", __FUNCTION__
));
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
;
1448 start_idx
= -1; /* Invalid index */
1451 dhd_free_tuple_entry(dhdp
, &head
);
1455 #endif /* USE_CID_CHECK || USE_DIRECT_VID_TAG */
1457 #ifdef USE_CID_CHECK
1458 /* Definitions for module information */
1459 #define MAX_VID_LEN 8
1461 #ifdef SUPPORT_MULTIPLE_BOARDTYPE
1462 #define MAX_BNAME_LEN 6
1466 unsigned char btype
[MAX_VID_LEN
];
1467 char bname
[MAX_BNAME_LEN
];
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 */
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 */
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 */
1489 #endif /* BCM4361_CHIP */
1490 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
1494 unsigned char vid
[MAX_VID_LEN
];
1495 char cid_info
[MAX_VNAME_LEN
];
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 */
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 */
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 */
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 */
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 */
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 */
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 */
1661 vid_info_t vid_info
[] = {
1662 { 0, { 0x00, }, { "samsung" } } /* Default: Not specified yet */
1664 #endif /* BCM_CHIP_ID */
1666 /* CID managment functions */
1669 dhd_get_cid_info(unsigned char *vid
, int vid_length
)
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
;
1680 DHD_ERROR(("%s : Can't find the cid info\n", __FUNCTION__
));
1685 dhd_check_module_cid(dhd_pub_t
*dhdp
)
1688 #ifndef DHD_EXPORT_CNTL_FILE
1689 const char *cidfilepath
= CIDINFO
;
1690 #endif /* DHD_EXPORT_CNTL_FILE */
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
];
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 */
1704 /* Try reading out from CIS */
1706 DHD_INFO(("%s: Couldn't read CIS info\n", __FUNCTION__
));
1710 DHD_INFO(("%s: Reading CIS from local buffer\n", __FUNCTION__
));
1712 dhd_dump_cis_buf(dhdp
, DUMP_CIS_SIZE
);
1713 #endif /* DUMP_CIS */
1715 idx
= dhd_find_tuple_idx_from_otp(dhdp
, CIS_TUPLE_TAG_VENDOR
, &tuple_length
);
1718 tuple_start
= &g_cis_buf
[idx
];
1722 max
= sizeof(vid_info
) / sizeof(vid_info_t
);
1723 for (idx
= 0; idx
< max
; idx
++) {
1724 cur_info
= &vid_info
[idx
];
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
;
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
;
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) {
1752 DHD_ERROR(("%s: cannot find default CID\n", __FUNCTION__
));
1756 #ifdef SUPPORT_MULTIPLE_BOARDTYPE
1757 idx
= dhd_find_tuple_idx_from_otp(dhdp
, CIS_TUPLE_TAG_BOARDTYPE
, &tuple_length
);
1759 btype_start
= &g_cis_buf
[idx
];
1760 boardtype_len
= tuple_length
;
1761 DHD_INFO(("%s: board type found.\n", __FUNCTION__
));
1765 #if defined(BCM4361_CHIP)
1766 vendor_b_info
= semco_PA_info
;
1767 max
= sizeof(semco_PA_info
) / sizeof(board_info_t
);
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
);
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
));
1794 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
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
);
1802 #endif /* SUPPORT_MULTIPLE_BOARDTYPE */
1803 strcpy(cid_info
, cur_info
->cid_info
);
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);
1809 strlcpy(cidinfostr
, cid_info
, MAX_VNAME_LEN
);
1810 #endif /* DHD_EXPORT_CNTL_FILE */
1815 #ifdef SUPPORT_MULTIPLE_MODULE_CIS
1816 #ifndef DHD_EXPORT_CNTL_FILE
1818 dhd_check_module(char *module_name
)
1820 char vname
[MAX_VNAME_LEN
];
1821 const char *cidfilepath
= CIDINFO
;
1824 memset(vname
, 0, sizeof(vname
));
1825 ret
= dhd_read_file(cidfilepath
, vname
, sizeof(vname
) - 1);
1829 DHD_INFO(("%s: This module is %s \n", __FUNCTION__
, vname
));
1830 return strstr(vname
, module_name
) ? TRUE
: FALSE
;
1834 dhd_check_module(char *module_name
)
1836 return strstr(cidinfostr
, module_name
) ? TRUE
: FALSE
;
1838 #endif /* !DHD_EXPORT_CNTL_FILE */
1841 dhd_check_module_b85a(void)
1844 char *vname_b85a
= "_b85a";
1846 if (dhd_check_module(vname_b85a
)) {
1847 DHD_INFO(("%s: It's a b85a module\n", __FUNCTION__
));
1850 DHD_INFO(("%s: It is not a b85a module\n", __FUNCTION__
));
1858 dhd_check_module_b90(void)
1861 char *vname_b90b
= "_b90b";
1862 char *vname_b90s
= "_b90s";
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
;
1871 DHD_ERROR(("%s: It's neither b90b nor b90s\n", __FUNCTION__
));
1877 #endif /* SUPPORT_MULTIPLE_MODULE_CIS */
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.
1887 dhd_check_module_bcm(char *module_type
, int index
, bool *is_murata_fem
)
1890 char vname
[MAX_VNAME_LEN
];
1892 #ifndef DHD_EXPORT_CNTL_FILE
1893 const char *cidfilepath
= CIDINFO
;
1894 #endif /* DHD_EXPORT_CNTL_FILE */
1896 memset(vname
, 0, sizeof(vname
));
1898 #ifndef DHD_EXPORT_CNTL_FILE
1899 ret
= dhd_read_file(cidfilepath
, vname
, sizeof(vname
) - 1);
1901 DHD_ERROR(("%s: failed to get module infomaion from .cid.info\n",
1906 strlcpy(vname
, cidinfostr
, MAX_VNAME_LEN
);
1907 #endif /* DHD_EXPORT_CNTL_FILE */
1909 for (i
= 1, ptr
= vname
; i
< index
&& ptr
; i
++) {
1910 ptr
= bcmstrstr(ptr
, "_");
1916 if (bcmstrnstr(vname
, MAX_VNAME_LEN
, CID_FEM_MURATA
, 5)) {
1917 *is_murata_fem
= TRUE
;
1921 memcpy(module_type
, ptr
, strlen(ptr
));
1923 DHD_ERROR(("%s: failed to get module infomaion\n", __FUNCTION__
));
1927 DHD_INFO(("%s: module type = %s \n", __FUNCTION__
, module_type
));
1931 #endif /* USE_CID_CHECK */
1933 #ifdef USE_DIRECT_VID_TAG
1935 dhd_check_module_cid(dhd_pub_t
*dhdp
)
1937 int ret
= BCME_ERROR
;
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 */
1946 /* Try reading out from CIS */
1948 DHD_INFO(("%s: Couldn't read CIS info\n", __FUNCTION__
));
1952 DHD_INFO(("%s: Reading CIS from local buffer\n", __FUNCTION__
));
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
);
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
]));
1962 DHD_ERROR(("%s: use nvram default\n", __FUNCTION__
));
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);
1972 strlcpy(cidinfostr
, cid_info
, MAX_VNAME_LEN
);
1973 #endif /* DHD_EXPORT_CNTL_FILE */
1975 DHD_INFO(("%s: cidinfostr %x%x\n", __FUNCTION__
,
1976 cidinfostr
[VENDOR_OFF
], cidinfostr
[MD_REV_OFF
]));
1981 dhd_check_stored_module_info(char *vid
)
1984 #ifndef DHD_EXPORT_CNTL_FILE
1985 const char *cidfilepath
= CIDINFO
;
1986 #endif /* DHD_EXPORT_CNTL_FILE */
1988 memset(vid
, 0, MAX_VID_LEN
);
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",
1998 strlcpy(vid
, cidinfostr
, MAX_VID_LEN
);
1999 #endif /* DHD_EXPORT_CNTL_FILE */
2001 if (vid
[0] == (char)0) {
2002 DHD_ERROR(("%s : Failed to get module information \n", __FUNCTION__
));
2006 DHD_INFO(("%s: stored VID= 0x%x%x\n", __FUNCTION__
, vid
[VENDOR_OFF
], vid
[MD_REV_OFF
]));
2009 #endif /* USE_DIRECT_VID_TAG */
2010 #endif /* DHD_USE_CISINFO */