1 /******************************************************************************
4 Lantiq Deutschland GmbH
6 For licensing information, see the file 'LICENSE' in the root folder of
9 ******************************************************************************/
11 * Accessor to the Card Information Section from EEPROM
19 #include "mtlk_eeprom.h"
20 #include "cis_manager.h"
22 #include "mtlk_tpcv4.h"
23 #include "mtlk_algorithms.h"
24 #include "mtlk_channels_propr.h"
25 #include "mtlk_coreui.h"
28 #define LOG_LOCAL_GID GID_CIS
29 #define LOG_LOCAL_FID 0
31 /*****************************************************************************
32 * Local type definitions
33 ******************************************************************************/
35 /* \cond DOXYGEN_IGNORE */
37 #define MTLK_IDEFS_PACKING 1
38 #include "mtlkidefs.h"
46 /* ... TPC data ... */
47 }__MTLK_IDATA tpc_header_t
;
49 /* Card setions TPL codes */
51 CIS_TPL_CODE_CID
= 0x80,
52 CIS_TPL_CODE_TPCG3
= 0x83,
53 CIS_TPL_CODE_LNA
= 0x82,
54 CIS_TPL_CODE_XTAL
= 0x84,
55 CIS_TPL_CODE_CRC
= 0x85,
56 CIS_TPL_CODE_NONE
= 0xFF
59 /* Card Information Structure header */
62 uint8 tpl_code
; /** see \ref cis_tpl_code_t */
64 /* ... CIS data ... */
65 }__MTLK_IDATA cis_header_t
;
67 #define MTLK_IDEFS_OFF
68 #include "mtlkidefs.h"
70 /*****************************************************************************
72 ******************************************************************************/
75 /*****************************************************************************
76 * Function implementation
77 ******************************************************************************/
80 _tpc_data_free(mtlk_eeprom_tpc_data_t
*data
)
87 if (NULL
!= data
->antenna
)
89 for(i
= 0; i
< data
->num_antennas
; i
++)
91 if (NULL
!= data
->antenna
[i
].point
)
93 mtlk_osal_mem_free(data
->antenna
[i
].point
);
94 data
->antenna
[i
].point
= NULL
;
98 mtlk_osal_mem_free(data
->antenna
);
102 mtlk_osal_mem_free(data
);
105 static mtlk_eeprom_tpc_data_t
*
106 _tpc_data_alloc(uint8 num_points
, uint8 num_antennas
)
109 mtlk_eeprom_tpc_data_t
*data
= NULL
;
111 data
= mtlk_osal_mem_alloc(sizeof(mtlk_eeprom_tpc_data_t
),
112 MTLK_MEM_TAG_TPC_DATA
);
116 memset(data
, 0, sizeof(mtlk_eeprom_tpc_data_t
));
117 data
->num_points
= num_points
;
118 data
->num_antennas
= num_antennas
;
120 data
->antenna
= mtlk_osal_mem_alloc(
121 sizeof(mtlk_eeprom_tpc_antenna_t
) * num_antennas
,
122 MTLK_MEM_TAG_TPC_ANTENNA
);
124 if (NULL
== data
->antenna
)
127 memset(data
->antenna
, 0,
128 sizeof(mtlk_eeprom_tpc_antenna_t
) * num_antennas
);
130 for(i
= 0; i
< num_antennas
; i
++)
132 data
->antenna
[i
].point
= mtlk_osal_mem_alloc(
133 sizeof(mtlk_eeprom_tpc_point_t
) * num_points
,
134 MTLK_MEM_TAG_TPC_POINT
);
136 if (NULL
== data
->antenna
[i
].point
)
139 memset(data
->antenna
[i
].point
, 0,
140 sizeof(mtlk_eeprom_tpc_point_t
) * num_points
);
146 _tpc_data_free(data
);
152 This function tries to find a CIS (Card information
153 section) in the buffer specified
155 \param id CIS block id to search for [I]
156 \param cis pointer to the CIS buffer [I]
157 \param cis_size size of CIS buffer in bytes [I]
158 \param data_size returns the size of CIS data [O]
159 \param next_cis pointer to the next CIS buffer [O]
162 NULL if CIS block not found, otherwise pointer to the CIS data
165 _cis_data_find (uint8 id
, cis_header_t
*cis
, int cis_size
, uint8
*data_size
, void** next_cis
)
169 /* The header starts with two bytes defining the size of the */
170 /* CIS section in bytes (not including these bytes and the next four). */
171 /* A value of 0h will be interpreted as "no CIS exist" */
172 /* Next comes TPL_LINK byte, defining number of bytes (N) exists */
173 /* at this CIS structure (not including the current byte). */
175 MTLK_ASSERT(NULL
!= cis
);
176 MTLK_ASSERT(NULL
!= data_size
);
178 while ((cis_size
>= sizeof(cis_header_t
)) && (cis
->tpl_code
!= CIS_TPL_CODE_NONE
))
181 data
+= sizeof(cis_header_t
);
183 if (cis
->data_size
+ sizeof(cis_header_t
) > cis_size
)
185 ELOG_DP("Partial CIS[0x%02X] detected at 0x%p",
190 if (cis
->tpl_code
== id
)
193 *next_cis
= data
+ cis
->data_size
;
195 *data_size
= cis
->data_size
;
200 cis_size
-= cis
->data_size
+ sizeof(cis_header_t
);
202 cis
= (cis_header_t
*) (data
+ cis
->data_size
);
209 This function tries to find end of CIS (Card information
210 section) in the buffer specified
212 \param cis pointer to the CIS buffer [I]
213 \param cis_size size of CIS buffer in bytes [I]
216 NULL if CIS end not found not found, otherwise pointer to the END of CIS data
219 _cis_find_end (cis_header_t
*cis
, int cis_size
)
223 /* The header starts with two bytes defining the size of the */
224 /* CIS section in bytes (not including these bytes and the next four). */
225 /* A value of 0h will be interpreted as "no CIS exist" */
226 /* Next comes TPL_LINK byte, defining number of bytes (N) exists */
227 /* at this CIS structure (not including the current byte). */
229 MTLK_ASSERT(NULL
!= cis
);
231 while (cis_size
>= sizeof(cis_header_t
))
235 if (cis
->tpl_code
== CIS_TPL_CODE_NONE
)
240 data
+= sizeof(cis_header_t
);
242 if (cis
->data_size
+ sizeof(cis_header_t
) > cis_size
)
244 ELOG_DP("Partial CIS[0x%02X] detected at 0x%p",
249 cis_size
-= cis
->data_size
+ sizeof(cis_header_t
);
251 cis
= (cis_header_t
*) (data
+ cis
->data_size
);
258 Perform data coping of TPC CIS item ver 4
260 \param item pointer to the TPC item [I]
261 \param data pointer to eeprom TPC data struct to fill in [O]
264 _parse_tpc4_item_data (mtlk_tpcv4_t
*item
, mtlk_eeprom_tpc_data_t
*data
)
268 data
->channel
= mtlk_tpcv4_get_channel(item
);
269 data
->band
= (mtlk_tpcv4_get_band(item
) == MTLK_TPC_BAND_2GHZ
) ? 1 : 0;
270 data
->spectrum_mode
= (mtlk_tpcv4_get_cb_flag(item
) == MTLK_TPC_CB
) ? 1 : 0;;
271 data
->freq
= channel_to_frequency(data
->channel
) + (data
->spectrum_mode
? 10: 0);
273 for(ant_id
= 0; ant_id
< data
->num_antennas
; ant_id
++)
275 data
->antenna
[ant_id
].tpc_value
=
276 mtlk_tpcv4_get_tpc_val(item
, ant_id
);
278 data
->antenna
[ant_id
].backoff_value
=
279 mtlk_tpcv4_get_backoff_packed(item
, ant_id
);
281 data
->antenna
[0].backoff_mult_value
=
282 mtlk_tpcv4_get_backoff_mul(item
, ant_id
);
284 for(pnt_id
= 0; pnt_id
< data
->num_points
; pnt_id
++)
286 mtlk_tpc_point_t point
;
287 mtlk_tpcv4_get_point(item
, ant_id
, pnt_id
, &point
);
288 data
->antenna
[ant_id
].point
[pnt_id
].x
= point
.x
;
289 data
->antenna
[ant_id
].point
[pnt_id
].y
= point
.y
;
293 ILOG5_DDD("TPC: ch=%d, band=%d, spectrum=%d", data
->channel
, data
->band
, data
->spectrum_mode
);
297 Perform parsing of TPC CIS item ver 4
299 \param item pointer to the TPC item [I]
300 \param parsed_cis pointer to eeprom CIS data struct to fill in [O]
303 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
306 _parse_tpc4_item (mtlk_tpcv4_t
*item
, mtlk_eeprom_cis_data_t
*parsed_cis
)
308 mtlk_eeprom_tpc_data_t
*data
=
309 _tpc_data_alloc(mtlk_tpcv4_get_num_points(item
),
310 NUM_TX_ANTENNAS_GEN3
/* TODO: Use info from configuration file */);
314 ELOG_V("Failed to allocate TPC data structure");
315 return MTLK_ERR_NO_MEM
;
318 ILOG5_D("TPC with %d points", data
->num_points
);
320 _parse_tpc4_item_data(item
, data
);
324 data
->next
= parsed_cis
->tpc_24
;
325 parsed_cis
->tpc_24
= data
;
329 data
->next
= parsed_cis
->tpc_52
;
330 parsed_cis
->tpc_52
= data
;
336 for (i
= 0; i
< data
->num_points
; i
++)
337 for(j
= 0; j
< data
->num_antennas
; j
++)
338 ILOG5_DDDD("ant%d: point_%d: (%u, %u)", j
, i
,
339 data
->antenna
[j
].point
[i
].x
,
340 data
->antenna
[j
].point
[i
].y
);
347 Cleanup enumerator for TPC list
350 _tpc_list_clean(mtlk_eeprom_tpc_data_t
*tpc
)
352 mtlk_eeprom_tpc_data_t
*prev
;
357 _tpc_data_free(prev
);
362 TCP data list accessor
364 static void* _tpc_list_get_next(void* item
)
366 return (void*) ((mtlk_eeprom_tpc_data_t
*)item
)->next
;
370 TPC data list updater
372 static void _tpc_list_set_next(void* item
, void* next
)
374 ((mtlk_eeprom_tpc_data_t
*)item
)->next
= (mtlk_eeprom_tpc_data_t
*) next
;
378 TPC data frequency comparator
380 static int _tpc_list_is_less(void* item1
, void* item2
)
382 return ((mtlk_eeprom_tpc_data_t
*)item1
)->freq
383 < ((mtlk_eeprom_tpc_data_t
*)item2
)->freq
;
387 TPC list sort routine
390 _tpc_list_sort(mtlk_eeprom_tpc_data_t
** list
)
400 Perform parsing of TPC CIS block ver 4
402 \param tpc pointer to the buffer with TPC items [I]
403 \param tpc_size total length of the TPC CIS [I]
404 \param parsed_cis pointer to eeprom data struct to fill in [O]
407 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
410 _parse_tpc4 (tpc_header_t
*tpc
, int tpc_size
,
411 mtlk_eeprom_cis_data_t
*parsed_cis
)
415 mtlk_tpcv4_t tpc4_parser
;
417 data
= (uint8
*)tpc
+ sizeof(tpc_header_t
);
419 /* calculate TPC data size */
420 tpc_size
-= sizeof(tpc_header_t
);
422 ILOG5_DD("size_24=%d, size_52=%d", tpc
->size_24
, tpc
->size_52
);
429 band
= mtlk_tpcv4_get_band_by_raw_buffer(data
);
431 MTLK_ASSERT( (MTLK_TPC_BAND_2GHZ
== band
) ||
432 (MTLK_TPC_BAND_5GHZ
== band
) );
434 data_size
= (MTLK_TPC_BAND_2GHZ
== band
) ?
435 tpc
->size_24
: tpc
->size_52
;
437 ILOG5_DD("Current TPC section offset = %u, left CIS size = %d",
438 data
- (uint8
*)tpc
, tpc_size
);
440 if (tpc_size
< data_size
)
442 ELOG_DD("TPC CIS contains partial structure: "
443 "expected size %d, left in CIS area: %d",
444 data_size
, tpc_size
);
445 return MTLK_ERR_NO_ENTRY
;
448 err
= mtlk_tpcv4_init(&tpc4_parser
, data
, data_size
);
449 if (MTLK_ERR_OK
!= err
)
451 ELOG_V("Failed to create TPC4 parser object");
455 err
= _parse_tpc4_item(&tpc4_parser
, parsed_cis
);
457 mtlk_tpcv4_cleanup(&tpc4_parser
);
459 if (MTLK_ERR_OK
!= err
)
461 ELOG_V("Failed to parse TPC4 item");
466 tpc_size
-= data_size
;
474 This routine provide parsing of CIS area from EEPROM
476 \param cis_area Pointer to CIS area [I]
477 \param parsed_cis Pointer to the buffer for parsed data [O]
480 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
483 mtlk_cis_area_parse (mtlk_cis_area_t
const *const cis_area
,
484 mtlk_eeprom_cis_data_t
*parsed_cis
)
487 void *cis_end
= NULL
;
489 tpc_header_t
*tpc
= NULL
;
490 mtlk_cis_cardid_t
*card_id
= NULL
;
491 uint16
*xtal_data
= NULL
;
492 mtlk_lna_cis_data_t
*lna_data
= NULL
;
494 MTLK_ASSERT(cis_area
);
495 MTLK_ASSERT(parsed_cis
);
497 parsed_cis
->tpc_valid
= 0;
499 /* Current implementation supports EEPROM versions 4 */
500 if (cis_area
->version1
!= 4)
502 ELOG_DD("Unsupported version of the EEPROM: %u.%u",
503 cis_area
->version1
, cis_area
->version0
);
504 return MTLK_ERR_NOT_SUPPORTED
;
507 parsed_cis
->version
= MTLK_MAKE_EEPROM_VERSION(
511 cis
= (((char*)cis_area
) + sizeof(mtlk_cis_area_t
));
512 cis_end
= cis
+ MAC_TO_HOST16(cis_area
->size
) - sizeof(mtlk_cis_area_t
);
514 card_id
= _cis_data_find(CIS_TPL_CODE_CID
, cis
, cis_end
- cis
,
518 ELOG_V("Can not find Card ID CIS");
519 return MTLK_ERR_EEPROM
;
522 if (cis_size
!= sizeof(*card_id
))
524 ELOG_V("Incorrect size of Card ID CIS");
525 return MTLK_ERR_EEPROM
;
528 /* check card_id values */
529 if ((card_id
->revision
< 'A') || (card_id
->revision
> 'Z'))
531 ELOG_DC("Invalid Card Revision: 0x%02x (%c)",
532 (int)card_id
->revision
,
533 (char)card_id
->revision
);
534 return MTLK_ERR_EEPROM
;
537 /* Handle optional LNA configuration */
538 lna_data
= _cis_data_find(CIS_TPL_CODE_LNA
, cis
, cis_end
- cis
,
540 if (NULL
!= lna_data
)
542 if (cis_size
!= sizeof(parsed_cis
->lna
))
544 ELOG_V("Incorrect size of LNA CIS");
545 return MTLK_ERR_EEPROM
;
548 memcpy(&parsed_cis
->lna
, lna_data
, sizeof(parsed_cis
->lna
));
552 parsed_cis
->lna
.lna_gain_bypass
= LNA_GAIN_BYPASS_DEFAULT_VALUE
;
553 parsed_cis
->lna
.lna_gain_high
= LNA_GAIN_HIGH_DEFAULT_VALUE
;
556 /* Handle optional XTAL configuration */
557 xtal_data
= _cis_data_find(CIS_TPL_CODE_XTAL
, cis
, cis_end
- cis
,
559 if (NULL
!= xtal_data
)
561 /* The Xtal section may be longer and include
562 additional byte for Temperature sensor */
563 if (cis_size
< sizeof(parsed_cis
->xtal
))
565 ELOG_V("Incorrect size of XTAL CIS");
566 return MTLK_ERR_EEPROM
;
569 /* copy Xtal value */
570 memcpy(&parsed_cis
->xtal
, xtal_data
, sizeof(parsed_cis
->xtal
));
574 parsed_cis
->xtal
= HOST_TO_MAC16(XTAL_DEFAULT_VALUE
);
577 /* CIS may contain multiple TPC areas, */
578 /* we have to parse all of them. */
579 tpc
= _cis_data_find(CIS_TPL_CODE_TPCG3
, cis
, cis_end
- cis
,
583 ELOG_V("At least one TPC CIS should be present");
584 return MTLK_ERR_EEPROM
;
589 if (MTLK_ERR_OK
!= _parse_tpc4(tpc
, cis_size
, parsed_cis
))
591 mtlk_eeprom_cis_data_clean(parsed_cis
);
592 return MTLK_ERR_EEPROM
;
595 tpc
= _cis_data_find(CIS_TPL_CODE_TPCG3
, cis
, cis_end
- cis
,
597 } while(NULL
!= tpc
);
599 _tpc_list_sort(&parsed_cis
->tpc_24
);
600 _tpc_list_sort(&parsed_cis
->tpc_52
);
602 parsed_cis
->tpc_valid
= 1;
604 parsed_cis
->card_id
= *card_id
;
606 /* If country code not recognized - indicate *unknown* country */
607 if (country_code_to_domain(parsed_cis
->card_id
.country_code
) == 0)
609 parsed_cis
->card_id
.country_code
= 0;
616 Cleanup routing for parsed CIS data
618 \param parsed_cis pointer to eeprom CIS data struct [I]
621 mtlk_eeprom_cis_data_clean (mtlk_eeprom_cis_data_t
*parsed_cis
)
623 _tpc_list_clean(parsed_cis
->tpc_24
);
624 _tpc_list_clean(parsed_cis
->tpc_52
);
628 This routine retrieve CRC value from CIS area of EEPROM
630 \param cis_area Pointer to CIS area [I]
631 \param crc_value Handle to the buffer for the CRC value
632 stored in the CIS area [O]
633 \param data_len Handle to the buffer for the length of CIS area data
634 used for CRC calculation [O]
635 Zero - if no CRC in the CIS area
638 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
641 mtlk_cis_crc_parse (mtlk_cis_area_t
const *const cis_area
,
642 uint32
*crc_value
, uint16
*chunk1_len
, uint16
*chunk2_len
)
645 void *cis_end
= NULL
;
647 uint32
*eeprom_crc
= NULL
;
648 uint32
*eeprom_cis_end
= NULL
;
650 MTLK_ASSERT(cis_area
);
651 MTLK_ASSERT(crc_value
);
652 MTLK_ASSERT(chunk1_len
);
653 MTLK_ASSERT(chunk2_len
);
658 /* Current implementation supports EEPROM versions 4 */
659 if (cis_area
->version1
!= 4)
661 ELOG_DD("Unsupported version of the EEPROM: %u.%u",
662 cis_area
->version1
, cis_area
->version0
);
663 return MTLK_ERR_NOT_SUPPORTED
;
666 cis
= (((char*)cis_area
) + sizeof(mtlk_cis_area_t
));
667 cis_end
= cis
+ MAC_TO_HOST16(cis_area
->size
) - sizeof(mtlk_cis_area_t
);
669 /* Handle optional CRC configuration */
670 eeprom_crc
= _cis_data_find(CIS_TPL_CODE_CRC
, cis
, cis_end
- cis
,
672 if (NULL
== eeprom_crc
)
675 if (cis_size
!= sizeof(*crc_value
))
677 ELOG_V("Incorrect size of CRC CIS");
678 return MTLK_ERR_EEPROM
;
682 memcpy(crc_value
, eeprom_crc
, sizeof(*crc_value
));
684 /* The whole CIS area are involved for CRC calculation, including
686 NOTE: CRC section could not be the last one in CIS area. */
687 *chunk1_len
= (uint16
)((void*)eeprom_crc
- (void*)cis_area
);
689 eeprom_cis_end
= _cis_find_end(cis
, cis_end
- cis
);
691 if (eeprom_cis_end
== NULL
)
693 ELOG_V("Incorrect eeprom, no CIS END");
694 return MTLK_ERR_EEPROM
;
697 *chunk2_len
= (uint16
)((void*)eeprom_cis_end
- ((void*)eeprom_crc
+ cis_size
));