/* Nota bene: avm-prom/prom-getenv-tffs.c is only for early development, as * it uses the TFFS function avm_urlader_env_get_value() which does not work * properly before mtd and TFFS initialisation is complete. */ #include #include #include #include static bool prom_env_initialized; static LIST_HEAD(prom_list); struct prom_entry { char *name; char *value; struct list_head list; }; static int prom_env_add(const char *env_name, char *env_value) { struct prom_entry *entry; if (!env_name || !env_value) return -EINVAL; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->name = kstrdup(env_name, GFP_KERNEL); if (!entry->name) goto err; /* env_value was allocated in memory by avm_urlader_env_get_value(). * prom_list now owns this memory and all responsibilities that follow */ entry->value = env_value; list_add_tail(&entry->list, &prom_list); return 0; err: kfree(entry); return -ENOMEM; } static int prom_env_init(struct notifier_block *nb, unsigned long action, void *data) { enum tffs3_module_state state = (enum tffs3_module_state)action; const struct _TFFS_Name_Table *tffs_env; char *tffs_env_val; int ret; if (state != tffs3_module_running) return NOTIFY_DONE; for (tffs_env = avm_urlader_get_nametable(); tffs_env && tffs_env->id; tffs_env++) { if (tffs_env->id == FLASH_FS_TABLE_VERSION || tffs_env->id == FLASH_FS_NAME_TABLE) continue; tffs_env_val = avm_urlader_env_get_value(tffs_env->Name); if (!tffs_env_val) continue; ret = prom_env_add(tffs_env->Name, tffs_env_val); if (ret) goto err_out; } /* We want to ensure that prom_env_initialized isn't set before * before it is actually initialized */ smp_store_release(&prom_env_initialized, true); return NOTIFY_OK; err_out: kfree(tffs_env_val); pr_err("Error reading urlader environment from TFFS (%d): prom_getenv won't work\n", ret); return NOTIFY_DONE; } static struct notifier_block tffs_notify_ready = { .notifier_call = prom_env_init, }; static int __init prom_env_register_tffs_notifier(void) { return blocking_notifier_chain_register(&tffs_state_notifier, &tffs_notify_ready); } device_initcall(prom_env_register_tffs_notifier); char *prom_getenv(char *var) { struct prom_entry *entry; if (!var || !prom_env_initialized) return NULL; list_for_each_entry(entry, &prom_list, list) if (!strcmp(entry->name, var)) return entry->value; return NULL; } EXPORT_SYMBOL(prom_getenv); MODULE_AUTHOR("AVM GmbH"); MODULE_DESCRIPTION("AVM prom_getenv() via TFFS (for development only)"); MODULE_LICENSE("GPL");