Initial commit
[wave300_rflib.git] / wireless / driver / rflib / shared / cis_manager.c
blob3504105a4f5d3dd34e93190588b69e2aaa0241df
1 /******************************************************************************
3 Copyright (c) 2012
4 Lantiq Deutschland GmbH
6 For licensing information, see the file 'LICENSE' in the root folder of
7 this software module.
9 ******************************************************************************/
11 * Accessor to the Card Information Section from EEPROM
14 #include "mtlkinc.h"
15 #include "mtlkerr.h"
16 #include "channels.h"
17 #include "mtlkaux.h"
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"
26 #include "mtlk_df.h"
28 #define LOG_LOCAL_GID GID_CIS
29 #define LOG_LOCAL_FID 0
31 /*****************************************************************************
32 * Local type definitions
33 ******************************************************************************/
35 /* \cond DOXYGEN_IGNORE */
36 #define MTLK_IDEFS_ON
37 #define MTLK_IDEFS_PACKING 1
38 #include "mtlkidefs.h"
39 /* \endcond */
41 /* CIS: TPC */
42 typedef struct
44 uint8 size_24;
45 uint8 size_52;
46 /* ... TPC data ... */
47 }__MTLK_IDATA tpc_header_t;
49 /* Card setions TPL codes */
50 typedef enum {
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
57 } cis_tpl_code_t;
59 /* Card Information Structure header */
60 typedef struct
62 uint8 tpl_code; /** see \ref cis_tpl_code_t */
63 uint8 data_size;
64 /* ... CIS data ... */
65 }__MTLK_IDATA cis_header_t;
67 #define MTLK_IDEFS_OFF
68 #include "mtlkidefs.h"
70 /*****************************************************************************
71 * Local definitions
72 ******************************************************************************/
73 #define TPC_DEBUG 0
75 /*****************************************************************************
76 * Function implementation
77 ******************************************************************************/
79 static void
80 _tpc_data_free(mtlk_eeprom_tpc_data_t *data)
82 int i;
84 if (NULL == data)
85 return;
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);
99 data->antenna = NULL;
102 mtlk_osal_mem_free(data);
105 static mtlk_eeprom_tpc_data_t *
106 _tpc_data_alloc(uint8 num_points, uint8 num_antennas)
108 int i;
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);
113 if (NULL == data)
114 return NULL;
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)
125 goto ERROR;
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)
137 goto ERROR;
139 memset(data->antenna[i].point, 0,
140 sizeof(mtlk_eeprom_tpc_point_t) * num_points);
143 return data;
145 ERROR:
146 _tpc_data_free(data);
148 return NULL;
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]
161 \return
162 NULL if CIS block not found, otherwise pointer to the CIS data
164 static void*
165 _cis_data_find (uint8 id, cis_header_t *cis, int cis_size, uint8 *data_size, void** next_cis)
167 uint8 *data = NULL;
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))
180 data = (uint8*) cis;
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",
186 cis->tpl_code, cis);
187 return NULL;
190 if (cis->tpl_code == id)
192 if (next_cis)
193 *next_cis = data + cis->data_size;
195 *data_size = cis->data_size;
197 return data;
200 cis_size -= cis->data_size + sizeof(cis_header_t);
202 cis = (cis_header_t *) (data + cis->data_size);
205 return NULL;
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]
215 \return
216 NULL if CIS end not found not found, otherwise pointer to the END of CIS data
218 static void*
219 _cis_find_end (cis_header_t *cis, int cis_size)
221 uint8 *data = NULL;
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))
233 data = (uint8*) cis;
235 if (cis->tpl_code == CIS_TPL_CODE_NONE)
237 return data;
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",
245 cis->tpl_code, cis);
246 return NULL;
249 cis_size -= cis->data_size + sizeof(cis_header_t);
251 cis = (cis_header_t *) (data + cis->data_size);
254 return NULL;
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]
263 static void
264 _parse_tpc4_item_data (mtlk_tpcv4_t *item, mtlk_eeprom_tpc_data_t *data)
266 int ant_id, pnt_id;
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]
302 \return
303 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
305 static int
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 */);
312 if (!data)
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);
322 if (data->band)
324 data->next = parsed_cis->tpc_24;
325 parsed_cis->tpc_24 = data;
327 else
329 data->next = parsed_cis->tpc_52;
330 parsed_cis->tpc_52 = data;
333 #if TPC_DEBUG
335 int i, j;
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);
342 #endif
343 return MTLK_ERR_OK;
347 Cleanup enumerator for TPC list
349 static void
350 _tpc_list_clean(mtlk_eeprom_tpc_data_t *tpc)
352 mtlk_eeprom_tpc_data_t *prev;
354 while (tpc) {
355 prev = tpc;
356 tpc = tpc->next;
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
389 static void
390 _tpc_list_sort(mtlk_eeprom_tpc_data_t** list)
392 mtlk_sort_slist(
393 (void**)list,
394 _tpc_list_get_next,
395 _tpc_list_set_next,
396 _tpc_list_is_less);
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]
406 \return
407 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
409 static int
410 _parse_tpc4 (tpc_header_t *tpc, int tpc_size,
411 mtlk_eeprom_cis_data_t *parsed_cis)
413 uint8 data_size = 0;
414 uint8 *data = NULL;
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);
424 while (tpc_size > 0)
426 MTLK_TPC_BAND band;
427 int err;
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");
452 return err;
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");
462 return err;
465 /* next item */
466 tpc_size -= data_size;
467 data += data_size;
468 } /* while */
470 return MTLK_ERR_OK;
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]
479 \return
480 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
482 int __MTLK_IFUNC
483 mtlk_cis_area_parse (mtlk_cis_area_t const *const cis_area,
484 mtlk_eeprom_cis_data_t *parsed_cis)
486 void *cis = NULL;
487 void *cis_end = NULL;
488 uint8 cis_size;
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(
508 cis_area->version1,
509 cis_area->version0);
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,
515 &cis_size, NULL);
516 if (!card_id)
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,
539 &cis_size, NULL);
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;
547 /* copy LNA value */
548 memcpy(&parsed_cis->lna, lna_data, sizeof(parsed_cis->lna));
550 else
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,
558 &cis_size, NULL);
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));
572 else
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,
580 &cis_size, &cis);
581 if (NULL == tpc)
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,
596 &cis_size, &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;
612 return MTLK_ERR_OK;
616 Cleanup routing for parsed CIS data
618 \param parsed_cis pointer to eeprom CIS data struct [I]
620 void __MTLK_IFUNC
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
637 \return
638 MTLK_ERR_OK on success or error value from \ref mtlk_error_t
640 int __MTLK_IFUNC
641 mtlk_cis_crc_parse (mtlk_cis_area_t const *const cis_area,
642 uint32 *crc_value, uint16 *chunk1_len, uint16 *chunk2_len)
644 void *cis = NULL;
645 void *cis_end = NULL;
646 uint8 cis_size;
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);
655 *chunk1_len = 0;
656 *chunk2_len = 0;
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,
671 &cis_size, NULL);
672 if (NULL == eeprom_crc)
673 return MTLK_ERR_OK;
675 if (cis_size != sizeof(*crc_value))
677 ELOG_V("Incorrect size of CRC CIS");
678 return MTLK_ERR_EEPROM;
681 /* copy CRC value */
682 memcpy(crc_value, eeprom_crc, sizeof(*crc_value));
684 /* The whole CIS area are involved for CRC calculation, including
685 CIS Header for CRC.
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));
699 return MTLK_ERR_OK;