1 /* 2 * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "cfg_all.h" 20 #include "cfg_define.h" 21 #include "cfg_dispatcher.h" 22 #include "cfg_ucfg_api.h" 23 #include "i_cfg.h" 24 #include "i_cfg_objmgr.h" 25 #include "qdf_atomic.h" 26 #include "qdf_list.h" 27 #include "qdf_mem.h" 28 #include "qdf_module.h" 29 #include "qdf_parse.h" 30 #include "qdf_status.h" 31 #include "qdf_str.h" 32 #include "qdf_trace.h" 33 #include "qdf_types.h" 34 #include "wlan_objmgr_psoc_obj.h" 35 36 /** 37 * struct cfg_value_store - backing store for an ini file 38 * @path: file path of the ini file 39 * @node: internal list node for keeping track of all the allocated stores 40 * @users: number of references on the store 41 * @values: a values struct containing the parsed values from the ini file 42 */ 43 struct cfg_value_store { 44 char *path; 45 qdf_list_node_t node; 46 qdf_atomic_t users; 47 struct cfg_values values; 48 }; 49 50 /* define/populate dynamic metadata lookup table */ 51 52 /** 53 * struct cfg_meta - configuration item metadata for dynamic lookup during parse 54 * @name: name of the config item used in the ini file (i.e. "gScanDwellTime") 55 * @item_handler: parsing callback based on the type of the config item 56 * @min: minimum value for use in bounds checking (min_len for strings) 57 * @max: maximum value for use in bounds checking (max_len for strings) 58 * @fallback: the fallback behavior to use when configured values are invalid 59 */ 60 struct cfg_meta { 61 const char *name; 62 const uint32_t field_offset; 63 void (*const item_handler)(struct cfg_value_store *store, 64 const struct cfg_meta *meta, 65 const char *value); 66 const int32_t min; 67 const int32_t max; 68 const enum cfg_fallback_behavior fallback; 69 }; 70 71 /* ini item handler functions */ 72 73 #define cfg_value_ptr(store, meta) \ 74 ((void *)&(store)->values + (meta)->field_offset) 75 76 static __attribute__((unused)) void 77 cfg_int_item_handler(struct cfg_value_store *store, 78 const struct cfg_meta *meta, 79 const char *str_value) 80 { 81 QDF_STATUS status; 82 int32_t *store_value = cfg_value_ptr(store, meta); 83 int32_t value; 84 85 status = qdf_int32_parse(str_value, &value); 86 if (QDF_IS_STATUS_ERROR(status)) { 87 cfg_err("%s=%s - Invalid format (status %d); Using default %d", 88 meta->name, str_value, status, *store_value); 89 return; 90 } 91 92 QDF_BUG(meta->min <= meta->max); 93 if (meta->min > meta->max) { 94 cfg_err("Invalid config item meta for %s", meta->name); 95 return; 96 } 97 98 if (value >= meta->min && value <= meta->max) { 99 *store_value = value; 100 return; 101 } 102 103 switch (meta->fallback) { 104 default: 105 QDF_DEBUG_PANIC("Unknown fallback method %d for cfg item '%s'", 106 meta->fallback, meta->name); 107 /* fall through */ 108 case CFG_VALUE_OR_DEFAULT: 109 /* store already contains default */ 110 break; 111 case CFG_VALUE_OR_CLAMP: 112 *store_value = __cfg_clamp(value, meta->min, meta->max); 113 break; 114 } 115 116 cfg_err("%s=%d - Out of range [%d, %d]; Using %d", 117 meta->name, value, meta->min, meta->max, *store_value); 118 } 119 120 static __attribute__((unused)) void 121 cfg_uint_item_handler(struct cfg_value_store *store, 122 const struct cfg_meta *meta, 123 const char *str_value) 124 { 125 QDF_STATUS status; 126 uint32_t *store_value = cfg_value_ptr(store, meta); 127 uint32_t value; 128 uint32_t min; 129 uint32_t max; 130 131 /** 132 * Since meta min and max are of type int32_t 133 * We need explicit type casting to avoid 134 * implicit wrap around for uint32_t type cfg data. 135 */ 136 min = (uint32_t)meta->min; 137 max = (uint32_t)meta->max; 138 139 status = qdf_uint32_parse(str_value, &value); 140 if (QDF_IS_STATUS_ERROR(status)) { 141 cfg_err("%s=%s - Invalid format (status %d); Using default %u", 142 meta->name, str_value, status, *store_value); 143 return; 144 } 145 146 QDF_BUG(min <= max); 147 if (min > max) { 148 cfg_err("Invalid config item meta for %s", meta->name); 149 return; 150 } 151 152 if (value >= min && value <= max) { 153 *store_value = value; 154 return; 155 } 156 157 switch (meta->fallback) { 158 default: 159 QDF_DEBUG_PANIC("Unknown fallback method %d for cfg item '%s'", 160 meta->fallback, meta->name); 161 /* fall through */ 162 case CFG_VALUE_OR_DEFAULT: 163 /* store already contains default */ 164 break; 165 case CFG_VALUE_OR_CLAMP: 166 *store_value = __cfg_clamp(value, min, max); 167 break; 168 } 169 170 cfg_err("%s=%u - Out of range [%d, %d]; Using %u", 171 meta->name, value, min, max, *store_value); 172 } 173 174 static __attribute__((unused)) void 175 cfg_bool_item_handler(struct cfg_value_store *store, 176 const struct cfg_meta *meta, 177 const char *str_value) 178 { 179 QDF_STATUS status; 180 bool *store_value = cfg_value_ptr(store, meta); 181 182 status = qdf_bool_parse(str_value, store_value); 183 if (QDF_IS_STATUS_SUCCESS(status)) 184 return; 185 186 cfg_err("%s=%s - Invalid format (status %d); Using default '%s'", 187 meta->name, str_value, status, *store_value ? "true" : "false"); 188 } 189 190 static __attribute__((unused)) void 191 cfg_string_item_handler(struct cfg_value_store *store, 192 const struct cfg_meta *meta, 193 const char *str_value) 194 { 195 char *store_value = cfg_value_ptr(store, meta); 196 qdf_size_t len; 197 198 QDF_BUG(meta->min >= 0); 199 QDF_BUG(meta->min <= meta->max); 200 if (meta->min < 0 || meta->min > meta->max) { 201 cfg_err("Invalid config item meta for %s", meta->name); 202 return; 203 } 204 205 /* ensure min length */ 206 len = qdf_str_nlen(str_value, meta->min); 207 if (len < meta->min) { 208 cfg_err("%s=%s - Too short; Using default '%s'", 209 meta->name, str_value, store_value); 210 return; 211 } 212 213 /* check max length */ 214 len += qdf_str_nlen(str_value + meta->min, meta->max - meta->min + 1); 215 if (len > meta->max) { 216 cfg_err("%s=%s - Too long; Using default '%s'", 217 meta->name, str_value, store_value); 218 return; 219 } 220 221 qdf_str_lcopy(store_value, str_value, meta->max + 1); 222 } 223 224 static __attribute__((unused)) void 225 cfg_mac_item_handler(struct cfg_value_store *store, 226 const struct cfg_meta *meta, 227 const char *str_value) 228 { 229 QDF_STATUS status; 230 struct qdf_mac_addr *store_value = cfg_value_ptr(store, meta); 231 232 status = qdf_mac_parse(str_value, store_value); 233 if (QDF_IS_STATUS_SUCCESS(status)) 234 return; 235 236 cfg_err("%s=%s - Invalid format (status %d); Using default " 237 QDF_MAC_ADDR_FMT, meta->name, str_value, status, 238 QDF_MAC_ADDR_REF(store_value->bytes)); 239 } 240 241 static __attribute__((unused)) void 242 cfg_ipv4_item_handler(struct cfg_value_store *store, 243 const struct cfg_meta *meta, 244 const char *str_value) 245 { 246 QDF_STATUS status; 247 struct qdf_ipv4_addr *store_value = cfg_value_ptr(store, meta); 248 249 status = qdf_ipv4_parse(str_value, store_value); 250 if (QDF_IS_STATUS_SUCCESS(status)) 251 return; 252 253 cfg_err("%s=%s - Invalid format (status %d); Using default " 254 QDF_IPV4_ADDR_STR, meta->name, str_value, status, 255 QDF_IPV4_ADDR_ARRAY(store_value->bytes)); 256 } 257 258 static __attribute__((unused)) void 259 cfg_ipv6_item_handler(struct cfg_value_store *store, 260 const struct cfg_meta *meta, 261 const char *str_value) 262 { 263 QDF_STATUS status; 264 struct qdf_ipv6_addr *store_value = cfg_value_ptr(store, meta); 265 266 status = qdf_ipv6_parse(str_value, store_value); 267 if (QDF_IS_STATUS_SUCCESS(status)) 268 return; 269 270 cfg_err("%s=%s - Invalid format (status %d); Using default " 271 QDF_IPV6_ADDR_STR, meta->name, str_value, status, 272 QDF_IPV6_ADDR_ARRAY(store_value->bytes)); 273 } 274 275 /* populate metadata lookup table */ 276 #undef __CFG_INI 277 #define __CFG_INI(_id, _mtype, _ctype, _name, _min, _max, _fallback, ...) \ 278 { \ 279 .name = _name, \ 280 .field_offset = qdf_offsetof(struct cfg_values, _id##_internal), \ 281 .item_handler = cfg_ ## _mtype ## _item_handler, \ 282 .min = _min, \ 283 .max = _max, \ 284 .fallback = _fallback, \ 285 }, 286 287 #define cfg_INT_item_handler cfg_int_item_handler 288 #define cfg_UINT_item_handler cfg_uint_item_handler 289 #define cfg_BOOL_item_handler cfg_bool_item_handler 290 #define cfg_STRING_item_handler cfg_string_item_handler 291 #define cfg_MAC_item_handler cfg_mac_item_handler 292 #define cfg_IPV4_item_handler cfg_ipv4_item_handler 293 #define cfg_IPV6_item_handler cfg_ipv6_item_handler 294 295 static const struct cfg_meta cfg_meta_lookup_table[] = { 296 CFG_ALL 297 }; 298 299 /* default store initializer */ 300 301 static void cfg_store_set_defaults(struct cfg_value_store *store) 302 { 303 #undef __CFG_INI 304 #define __CFG_INI(id, mtype, ctype, name, min, max, fallback, desc, def...) \ 305 ctype id = def; 306 307 CFG_ALL 308 309 #undef __CFG_INI_STRING 310 #define __CFG_INI_STRING(id, mtype, ctype, name, min_len, max_len, ...) \ 311 qdf_str_lcopy((char *)&store->values.id##_internal, id, (max_len) + 1); 312 313 #undef __CFG_INI 314 #define __CFG_INI(id, mtype, ctype, name, min, max, fallback, desc, def...) \ 315 *(ctype *)&store->values.id##_internal = id; 316 317 CFG_ALL 318 } 319 320 static const struct cfg_meta *cfg_lookup_meta(const char *name) 321 { 322 int i; 323 324 QDF_BUG(name); 325 if (!name) 326 return NULL; 327 328 /* linear search for now; optimize in the future if needed */ 329 for (i = 0; i < QDF_ARRAY_SIZE(cfg_meta_lookup_table); i++) { 330 const struct cfg_meta *meta = &cfg_meta_lookup_table[i]; 331 332 if (qdf_str_eq(name, meta->name)) 333 return meta; 334 } 335 336 return NULL; 337 } 338 339 static QDF_STATUS 340 cfg_ini_item_handler(void *context, const char *key, const char *value) 341 { 342 struct cfg_value_store *store = context; 343 const struct cfg_meta *meta; 344 345 meta = cfg_lookup_meta(key); 346 if (!meta) { 347 /* TODO: promote to 'err' or 'warn' once legacy is ported */ 348 cfg_debug("Unknown config item '%s'", key); 349 return QDF_STATUS_SUCCESS; 350 } 351 352 QDF_BUG(meta->item_handler); 353 if (!meta->item_handler) 354 return QDF_STATUS_SUCCESS; 355 356 meta->item_handler(store, meta, value); 357 358 return QDF_STATUS_SUCCESS; 359 } 360 361 static QDF_STATUS cfg_ini_section_handler(void *context, const char *name) 362 { 363 cfg_err("Unexpected section '%s'. Sections are not supported.", name); 364 365 return QDF_STATUS_SUCCESS; 366 } 367 368 #define cfg_assert_success(expr) \ 369 do { \ 370 QDF_STATUS __assert_status = (expr); \ 371 QDF_BUG(QDF_IS_STATUS_SUCCESS(__assert_status)); \ 372 } while (0) 373 374 static bool __cfg_is_init; 375 static struct cfg_value_store *__cfg_global_store; 376 static qdf_list_t __cfg_stores_list; 377 static qdf_spinlock_t __cfg_stores_lock; 378 379 struct cfg_psoc_ctx { 380 struct cfg_value_store *store; 381 }; 382 383 static QDF_STATUS 384 cfg_store_alloc(const char *path, struct cfg_value_store **out_store) 385 { 386 QDF_STATUS status; 387 struct cfg_value_store *store; 388 389 cfg_enter(); 390 391 store = qdf_mem_malloc(sizeof(*store)); 392 if (!store) 393 return QDF_STATUS_E_NOMEM; 394 395 status = qdf_str_dup(&store->path, path); 396 if (QDF_IS_STATUS_ERROR(status)) 397 goto free_store; 398 399 status = qdf_atomic_init(&store->users); 400 if (QDF_IS_STATUS_ERROR(status)) 401 goto free_path; 402 qdf_atomic_inc(&store->users); 403 404 qdf_spin_lock_bh(&__cfg_stores_lock); 405 status = qdf_list_insert_back(&__cfg_stores_list, &store->node); 406 qdf_spin_unlock_bh(&__cfg_stores_lock); 407 if (QDF_IS_STATUS_ERROR(status)) 408 goto free_path; 409 410 *out_store = store; 411 412 return QDF_STATUS_SUCCESS; 413 414 free_path: 415 qdf_mem_free(store->path); 416 417 free_store: 418 qdf_mem_free(store); 419 420 return status; 421 } 422 423 static void cfg_store_free(struct cfg_value_store *store) 424 { 425 QDF_STATUS status; 426 427 cfg_enter(); 428 429 qdf_spin_lock_bh(&__cfg_stores_lock); 430 status = qdf_list_remove_node(&__cfg_stores_list, &store->node); 431 qdf_spin_unlock_bh(&__cfg_stores_lock); 432 if (QDF_IS_STATUS_ERROR(status)) 433 QDF_DEBUG_PANIC("Failed config store list removal; status:%d", 434 status); 435 436 qdf_mem_free(store->path); 437 qdf_mem_free(store); 438 } 439 440 static QDF_STATUS 441 cfg_store_get(const char *path, struct cfg_value_store **out_store) 442 { 443 QDF_STATUS status; 444 qdf_list_node_t *node; 445 446 *out_store = NULL; 447 448 qdf_spin_lock_bh(&__cfg_stores_lock); 449 status = qdf_list_peek_front(&__cfg_stores_list, &node); 450 while (QDF_IS_STATUS_SUCCESS(status)) { 451 struct cfg_value_store *store = 452 qdf_container_of(node, struct cfg_value_store, node); 453 454 if (qdf_str_eq(path, store->path)) { 455 qdf_atomic_inc(&store->users); 456 *out_store = store; 457 break; 458 } 459 460 status = qdf_list_peek_next(&__cfg_stores_list, node, &node); 461 } 462 qdf_spin_unlock_bh(&__cfg_stores_lock); 463 464 return status; 465 } 466 467 static void cfg_store_put(struct cfg_value_store *store) 468 { 469 if (qdf_atomic_dec_and_test(&store->users)) 470 cfg_store_free(store); 471 } 472 473 static struct cfg_psoc_ctx *cfg_psoc_get_ctx(struct wlan_objmgr_psoc *psoc) 474 { 475 struct cfg_psoc_ctx *psoc_ctx; 476 477 psoc_ctx = cfg_psoc_get_priv(psoc); 478 QDF_BUG(psoc_ctx); 479 480 return psoc_ctx; 481 } 482 483 struct cfg_values *cfg_psoc_get_values(struct wlan_objmgr_psoc *psoc) 484 { 485 return &cfg_psoc_get_ctx(psoc)->store->values; 486 } 487 qdf_export_symbol(cfg_psoc_get_values); 488 489 static QDF_STATUS 490 cfg_ini_parse_to_store(const char *path, struct cfg_value_store *store) 491 { 492 QDF_STATUS status; 493 494 status = qdf_ini_parse(path, store, cfg_ini_item_handler, 495 cfg_ini_section_handler); 496 if (QDF_IS_STATUS_ERROR(status)) 497 cfg_err("Failed to parse *.ini file @ %s; status:%d", 498 path, status); 499 500 return status; 501 } 502 503 QDF_STATUS cfg_parse_to_psoc_store(struct wlan_objmgr_psoc *psoc, 504 const char *path) 505 { 506 return cfg_ini_parse_to_store(path, cfg_psoc_get_ctx(psoc)->store); 507 } 508 509 qdf_export_symbol(cfg_parse_to_psoc_store); 510 511 QDF_STATUS cfg_parse_to_global_store(const char *path) 512 { 513 if (!__cfg_global_store) { 514 cfg_err("Global INI store is not valid"); 515 return QDF_STATUS_E_NOMEM; 516 } 517 518 return cfg_ini_parse_to_store(path, __cfg_global_store); 519 } 520 521 qdf_export_symbol(cfg_parse_to_global_store); 522 523 524 static QDF_STATUS 525 cfg_store_print(struct wlan_objmgr_psoc *psoc) 526 { 527 struct cfg_value_store *store; 528 struct cfg_psoc_ctx *psoc_ctx; 529 530 cfg_enter(); 531 532 psoc_ctx = cfg_psoc_get_ctx(psoc); 533 if (!psoc_ctx) 534 return QDF_STATUS_E_FAILURE; 535 536 store = psoc_ctx->store; 537 if (!store) 538 return QDF_STATUS_E_FAILURE; 539 540 #undef __CFG_INI_MAC 541 #define __CFG_INI_MAC(id, mtype, ctype, name, desc, def...) \ 542 cfg_nofl_debug("%s "QDF_MAC_ADDR_FMT, name, \ 543 QDF_MAC_ADDR_REF((&store->values.id##_internal)->bytes)); 544 545 #undef __CFG_INI_IPV4 546 #define __CFG_INI_IPV4(id, mtype, ctype, name, desc, def...) \ 547 cfg_nofl_debug("%s %pI4", name, (&store->values.id##_internal)->bytes); 548 549 #undef __CFG_INI_IPV6 550 #define __CFG_INI_IPV6(id, mtype, ctype, name, desc, def...) \ 551 cfg_nofl_debug("%s %pI6c", name, (&store->values.id##_internal)->bytes); 552 553 #undef __CFG_INI 554 #define __CFG_INI(id, mtype, ctype, name, min, max, fallback, desc, def...) \ 555 cfg_nofl_debug("%s %u", name, *(ctype *)&store->values.id##_internal); 556 557 #undef __CFG_INI_STRING 558 #define __CFG_INI_STRING(id, mtype, ctype, name, min_len, max_len, ...) \ 559 cfg_nofl_debug("%s %s", name, (char *)&store->values.id##_internal); 560 561 CFG_ALL 562 563 #undef __CFG_INI_MAC 564 #undef __CFG_INI_IPV4 565 #undef __CFG_INI_IPV6 566 #undef __CFG_INI 567 #undef __CFG_INI_STRING 568 569 cfg_exit(); 570 return QDF_STATUS_SUCCESS; 571 } 572 573 static QDF_STATUS 574 cfg_ini_config_print(struct wlan_objmgr_psoc *psoc, uint8_t *buf, 575 ssize_t *plen, ssize_t buflen) 576 { 577 struct cfg_value_store *store; 578 struct cfg_psoc_ctx *psoc_ctx; 579 ssize_t len; 580 ssize_t total_len = buflen; 581 582 cfg_enter(); 583 584 psoc_ctx = cfg_psoc_get_ctx(psoc); 585 if (!psoc_ctx) 586 return QDF_STATUS_E_FAILURE; 587 588 store = psoc_ctx->store; 589 if (!store) 590 return QDF_STATUS_E_FAILURE; 591 592 #undef __CFG_INI_MAC 593 #define __CFG_INI_MAC(id, mtype, ctype, name, desc, def...) \ 594 do { \ 595 len = qdf_scnprintf(buf, buflen, "%s "QDF_MAC_ADDR_FMT"\n", \ 596 name, \ 597 QDF_MAC_ADDR_REF((&store->values.id##_internal)->bytes)); \ 598 buf += len; \ 599 buflen -= len; \ 600 } while (0); 601 602 #undef __CFG_INI_IPV4 603 #define __CFG_INI_IPV4(id, mtype, ctype, name, desc, def...) \ 604 do { \ 605 len = qdf_scnprintf(buf, buflen, "%s %pI4\n", name, \ 606 (&store->values.id##_internal)->bytes); \ 607 buf += len; \ 608 buflen -= len; \ 609 } while (0); 610 611 #undef __CFG_INI_IPV6 612 #define __CFG_INI_IPV6(id, mtype, ctype, name, desc, def...) \ 613 do { \ 614 len = qdf_scnprintf(buf, buflen, "%s %pI6c\n", name, \ 615 (&store->values.id##_internal)->bytes); \ 616 buf += len; \ 617 buflen -= len; \ 618 } while (0); 619 620 #undef __CFG_INI 621 #define __CFG_INI(id, mtype, ctype, name, min, max, fallback, desc, def...) \ 622 do { \ 623 len = qdf_scnprintf(buf, buflen, "%s %u\n", name, \ 624 *(ctype *)&store->values.id##_internal); \ 625 buf += len; \ 626 buflen -= len; \ 627 } while (0); 628 629 #undef __CFG_INI_STRING 630 #define __CFG_INI_STRING(id, mtype, ctype, name, min_len, max_len, ...) \ 631 do { \ 632 len = qdf_scnprintf(buf, buflen, "%s %s\n", name, \ 633 (char *)&store->values.id##_internal); \ 634 buf += len; \ 635 buflen -= len; \ 636 } while (0); 637 638 CFG_ALL 639 640 #undef __CFG_INI_MAC 641 #undef __CFG_INI_IPV4 642 #undef __CFG_INI_IPV6 643 #undef __CFG_INI 644 #undef __CFG_INI_STRING 645 646 *plen = total_len - buflen; 647 cfg_exit(); 648 649 return QDF_STATUS_SUCCESS; 650 } 651 652 QDF_STATUS ucfg_cfg_store_print(struct wlan_objmgr_psoc *psoc) 653 { 654 return cfg_store_print(psoc); 655 } 656 657 QDF_STATUS ucfg_cfg_ini_config_print(struct wlan_objmgr_psoc *psoc, 658 uint8_t *buf, ssize_t *plen, 659 ssize_t buflen) 660 { 661 return cfg_ini_config_print(psoc, buf, plen, buflen); 662 } 663 664 static QDF_STATUS 665 cfg_on_psoc_create(struct wlan_objmgr_psoc *psoc, void *context) 666 { 667 QDF_STATUS status; 668 struct cfg_psoc_ctx *psoc_ctx; 669 670 cfg_enter(); 671 672 QDF_BUG(__cfg_global_store); 673 if (!__cfg_global_store) 674 return QDF_STATUS_E_FAILURE; 675 676 psoc_ctx = qdf_mem_malloc(sizeof(*psoc_ctx)); 677 if (!psoc_ctx) 678 return QDF_STATUS_E_NOMEM; 679 680 qdf_atomic_inc(&__cfg_global_store->users); 681 psoc_ctx->store = __cfg_global_store; 682 683 status = cfg_psoc_set_priv(psoc, psoc_ctx); 684 if (QDF_IS_STATUS_ERROR(status)) 685 goto put_store; 686 687 return QDF_STATUS_SUCCESS; 688 689 put_store: 690 cfg_store_put(__cfg_global_store); 691 qdf_mem_free(psoc_ctx); 692 693 return status; 694 } 695 696 static QDF_STATUS 697 cfg_on_psoc_destroy(struct wlan_objmgr_psoc *psoc, void *context) 698 { 699 QDF_STATUS status; 700 struct cfg_psoc_ctx *psoc_ctx; 701 702 cfg_enter(); 703 704 psoc_ctx = cfg_psoc_get_ctx(psoc); 705 status = cfg_psoc_unset_priv(psoc, psoc_ctx); 706 707 cfg_store_put(psoc_ctx->store); 708 qdf_mem_free(psoc_ctx); 709 710 return status; 711 } 712 713 QDF_STATUS cfg_dispatcher_init(void) 714 { 715 QDF_STATUS status; 716 717 cfg_enter(); 718 719 QDF_BUG(!__cfg_is_init); 720 if (__cfg_is_init) 721 return QDF_STATUS_E_INVAL; 722 723 qdf_list_create(&__cfg_stores_list, 0); 724 qdf_spinlock_create(&__cfg_stores_lock); 725 726 status = cfg_psoc_register_create(cfg_on_psoc_create); 727 if (QDF_IS_STATUS_ERROR(status)) 728 return status; 729 730 status = cfg_psoc_register_destroy(cfg_on_psoc_destroy); 731 if (QDF_IS_STATUS_ERROR(status)) 732 goto unreg_create; 733 734 __cfg_is_init = true; 735 736 return QDF_STATUS_SUCCESS; 737 738 unreg_create: 739 cfg_assert_success(cfg_psoc_unregister_create(cfg_on_psoc_create)); 740 741 return status; 742 } 743 744 QDF_STATUS cfg_dispatcher_deinit(void) 745 { 746 cfg_enter(); 747 748 QDF_BUG(__cfg_is_init); 749 if (!__cfg_is_init) 750 return QDF_STATUS_E_INVAL; 751 752 __cfg_is_init = false; 753 754 cfg_assert_success(cfg_psoc_unregister_create(cfg_on_psoc_create)); 755 cfg_assert_success(cfg_psoc_unregister_destroy(cfg_on_psoc_destroy)); 756 757 qdf_spin_lock_bh(&__cfg_stores_lock); 758 QDF_BUG(qdf_list_empty(&__cfg_stores_list)); 759 qdf_spin_unlock_bh(&__cfg_stores_lock); 760 761 qdf_spinlock_destroy(&__cfg_stores_lock); 762 qdf_list_destroy(&__cfg_stores_list); 763 764 return QDF_STATUS_SUCCESS; 765 } 766 767 QDF_STATUS cfg_parse(const char *path) 768 { 769 QDF_STATUS status; 770 struct cfg_value_store *store; 771 772 cfg_enter(); 773 774 QDF_BUG(!__cfg_global_store); 775 if (__cfg_global_store) 776 return QDF_STATUS_E_INVAL; 777 778 status = cfg_store_alloc(path, &store); 779 if (QDF_IS_STATUS_ERROR(status)) 780 return status; 781 782 cfg_store_set_defaults(store); 783 784 status = cfg_ini_parse_to_store(path, store); 785 if (QDF_IS_STATUS_ERROR(status)) 786 goto free_store; 787 788 __cfg_global_store = store; 789 790 return QDF_STATUS_SUCCESS; 791 792 free_store: 793 cfg_store_free(store); 794 795 return status; 796 } 797 798 void cfg_release(void) 799 { 800 cfg_enter(); 801 802 QDF_BUG(__cfg_global_store); 803 if (!__cfg_global_store) 804 return; 805 806 cfg_store_put(__cfg_global_store); 807 __cfg_global_store = NULL; 808 } 809 810 QDF_STATUS cfg_psoc_parse(struct wlan_objmgr_psoc *psoc, const char *path) 811 { 812 QDF_STATUS status; 813 struct cfg_value_store *store; 814 struct cfg_psoc_ctx *psoc_ctx; 815 816 cfg_enter(); 817 818 QDF_BUG(__cfg_global_store); 819 if (!__cfg_global_store) 820 return QDF_STATUS_E_INVAL; 821 822 QDF_BUG(__cfg_is_init); 823 if (!__cfg_is_init) 824 return QDF_STATUS_E_INVAL; 825 826 QDF_BUG(psoc); 827 if (!psoc) 828 return QDF_STATUS_E_INVAL; 829 830 QDF_BUG(path); 831 if (!path) 832 return QDF_STATUS_E_INVAL; 833 834 psoc_ctx = cfg_psoc_get_ctx(psoc); 835 836 QDF_BUG(psoc_ctx->store == __cfg_global_store); 837 if (psoc_ctx->store != __cfg_global_store) 838 return QDF_STATUS_SUCCESS; 839 840 /* check if @path has been parsed before */ 841 status = cfg_store_get(path, &store); 842 if (QDF_IS_STATUS_ERROR(status)) { 843 status = cfg_store_alloc(path, &store); 844 if (QDF_IS_STATUS_ERROR(status)) 845 return status; 846 847 /* inherit global configuration */ 848 qdf_mem_copy(&store->values, &__cfg_global_store->values, 849 sizeof(store->values)); 850 851 status = cfg_ini_parse_to_store(path, store); 852 if (QDF_IS_STATUS_ERROR(status)) 853 goto put_store; 854 } 855 856 psoc_ctx->store = store; 857 cfg_store_put(__cfg_global_store); 858 859 return QDF_STATUS_SUCCESS; 860 861 put_store: 862 cfg_store_put(store); 863 864 return status; 865 } 866 867 qdf_export_symbol(cfg_psoc_parse); 868 869