#include #include #include #include #include #include #include #if defined(CONFIG_TFFS) #include #endif #if defined(CONFIG_MTD_UBI) #include #include #endif #include #include /* * Container-Aufbau: * (mtd-nand "ubi" (ubivol "avm_filesys_0" (mtd-gluebi "filesystem"), ... )) * * Ablauf: * * (Im Falle von CONFIG_AVM_MTD_LEGACY_PLATRAM: * 0. mtdram1= ist gesetzt und prepare_ram_resource bereitet * avm_mtd_ram_resource vor.) * 1. init registriert notification handler * 2. mtd_add_handler wird über neue devices in RAM oder NAND informiert. * a) abhängig von mtd->name wird der root= parameter gesetzt, wobei RAM * priorisiert wird * b) "nand-tffs" wird für TFFS3 registriert * c) für "ubi" wird der ubi= parameter gesetz * d) "urlader" wird als urlader_mtd gemerkt (z.B. für prom_getenv) * 3. gluebi stellt mtdblock devices auf ubi bereit und triggert * mtd_add_handler, was mtd->name ändert und wieder nach Punkt 2 vorgeht. * * Wenn UBI_BLOCK vorhanden ist, wird alternativ zu 3. der ubi_add_notifier * benutzt. */ #ifdef CONFIG_AVM_MTD_LEGACY_PLATRAM struct resource avm_mtd_ram_resource[] = { { /* for RAM loaded filesystem */ .start = 0, // set by mtdram_setup() .end = 0, // dito .flags = IORESOURCE_MEM, } }; static struct platdata_mtd_ram ram_data = { .mapname = "ram-filesystem", .bankwidth = 4, /* TODO warum 4? -phu */ // .partitions = // .nr_partitions = }; static struct platform_device ram_device = { .name = "mtd-ram", .id = -1, .dev = { .platform_data = &ram_data }, .num_resources = 1, //.resource = }; #endif /* CONFIG_AVM_MTD_LEGACY_PLATRAM */ #if defined(CONFIG_MTD_UBI) struct mtd_entry { char *urlader_name; char *runtime_name_0; char *runtime_name_1; }; struct mtd_entry mtd_names_ubi[] = { { "avm_filesys_0", "filesystem", "reserved-filesystem" }, { "avm_filesys_1", "reserved-filesystem", "filesystem" }, { "avm_config", "config", "config" }, { "avm_userdata", "nand-filesystem", "nand-filesystem" }, { NULL, NULL, NULL }, }; #endif static int root_from_ramfs = 0; // Immer das root device aus dem RAM als letztes aufsetzen. extern int __init root_dev_setup(char *line); extern int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp); /* * search a name table for runtime MTD name. Returns original name if no * substitution is found */ #if defined(CONFIG_MTD_UBI) static char *get_name(struct mtd_entry *nametable, const char *name) { unsigned int i; unsigned long linux_fs_start; char *p, *new_name; int res; linux_fs_start = 0; new_name = (char *)name; p = prom_getenv("linux_fs_start"); if (p != NULL) { res = kstrtoul(p, 0, &linux_fs_start); if (res == 0) { switch (linux_fs_start) { case 0: case 1: break; default: linux_fs_start = 0; } } } i = 0; while (nametable[i].urlader_name != NULL) { if (!strcmp(name, nametable[i].urlader_name)) { new_name = (linux_fs_start == 0) ? nametable[i].runtime_name_0 : nametable[i].runtime_name_1; break; } ++i; } return new_name; } void rename_ubi(struct mtd_info *mtd) { char *mtdname, *oldname; pr_debug("[%s] entering ", __func__); if (!mtd->name) { pr_info("[%s] Called for unnamed mtd", __func__); return; } if (mtd->type != MTD_UBIVOLUME) { pr_debug(" skipping mtd %s. Not an UBI volume\n", mtd->name); return; } mtdname = get_name(&mtd_names_ubi[0], mtd->name); if (mtdname != mtd->name) { // gluebi allocates name strings dynamiccaly and frees them on // volume removal oldname = (char *)mtd->name; mtd->name = kstrdup(mtdname, GFP_KERNEL); if (mtd->name != NULL) { pr_debug("[%s] renamed mtd %s -> %s\n", __func__, oldname, mtd->name); // FIXME: is it safe to free the string or should we just drop it? kfree(oldname); } else { mtd->name = oldname; pr_warning("[%s] Unable to rename mtd %s.\n", __func__, mtd->name); } } } #endif void __init mtd_add_handler(struct mtd_info *mtd) { char root_dev[64]; #if defined(CONFIG_MTD_UBI) unsigned char *recover = NULL, *p = prom_getenv("firmware_info"); /*--------------------------------------------------------------------------------*\ * beim recover soll das UBI gelöscht und neu angelegt werden, also wird bei * gesetzten recover nicht das UBI gemountet \*--------------------------------------------------------------------------------*/ if (p) recover = strstr(p, "recovered=2"); if (mtd->type == MTD_UBIVOLUME) rename_ubi(mtd); #endif pr_debug("[%s] entered\n", __func__); if (!root_from_ramfs && (strcmp(mtd->name, "rootfs_ram") == 0 || strcmp(mtd->name, "rootfs_spi") == 0)) { int ret; ret = snprintf(root_dev, sizeof(root_dev), "/dev/mtdblock%d", mtd->index); if (ret >= sizeof(root_dev)) { pr_emerg("[%s] Unable to generate root device name!\n", mtd->name); return; } pr_info("[%s] %s (%s) will be used as root device\n", __func__, mtd->name, root_dev); root_dev_setup(root_dev); if (strcmp(mtd->name, "rootfs_ram") == 0) root_from_ramfs = 1; #if defined(CONFIG_TFFS) #if defined(CONFIG_TFFS_DEV_LEGACY) } else if (strcmp(mtd->name, "tffs (1)") == 0) { tffs_mtd[0] = mtd->index; pr_debug("[%s] mtd%d[%s] set tffs mtd 0\n", __func__, mtd->index, mtd->name); } else if (strcmp(mtd->name, "tffs (2)") == 0) { tffs_mtd[1] = mtd->index; pr_debug("[%s] mtd%d[%s] set tffs mtd 1\n", __func__, mtd->index, mtd->name); #endif } else if (!strcmp(mtd->name, "nand-tffs")) { if (!avm_dt_urlader_env_is_enabled()) { TFFS3_Register_NAND(mtd); pr_debug("[%s] tffs3 on MTD %s\n", __func__, mtd->name); } else { pr_debug("[%s] ignored tffs3 on MTD %s: using the device tree\n", __func__, mtd->name); } #endif #if defined(CONFIG_MTD_UBI) } else if (!strcmp(mtd->name, "ubi")) { if (!recover) { ubi_mtd_param_parse(mtd->name, NULL); pr_debug("[%s] UBI on MTD %s\n", __func__, mtd->name); } else { pr_debug("[%s] box recovered - %s\n", __func__, recover); } #endif } else { pr_debug("[%s] mtd \"%s\" is not handled by me.\n", __func__, mtd->name); } if (!strcmp(mtd->name, "filesystem") && config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV)) { pr_notice("mtd: device %d (%s) set to be root filesystem\n", mtd->index, mtd->name); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); } } void mtd_rm_handler(struct mtd_info *mtd) { pr_debug("[%s] mtd \"%s\" passing by.\n", __func__, mtd->name); } static struct mtd_notifier mtd_notifier_ops = { .add = mtd_add_handler, .remove = mtd_rm_handler }; #if defined(CONFIG_MTD_UBI) static struct mtd_notifier mtd_postinit_notifier_ops = { .add = rename_ubi, .remove = mtd_rm_handler }; #endif #ifdef CONFIG_AVM_MTD_LEGACY_PLATRAM static int register_ram_device(struct resource *ram_resource) { pr_debug("[%s] registering ram device now\n", __func__); ram_device.resource = &ram_resource[0]; if (platform_device_register(&ram_device)) { pr_debug("[%s] failed to register plat_mem device\n", __func__); } return 0; } #endif static int __init avm_mtd_init(void) { pr_debug("[%s] entered\n", __func__); register_mtd_user(&mtd_notifier_ops); #ifdef CONFIG_AVM_MTD_LEGACY_PLATRAM if (avm_mtd_ram_resource[0].start != avm_mtd_ram_resource[0].end) { /* register plat_ram mtd device as per cmdline request */ register_ram_device(avm_mtd_ram_resource); } #endif return 0; } /*--------------------------------------------------------------------------------*\ * this is called from free_initmem as late_initcall is still too early * * avm_mtd_cleanup should not located in the __init sections, the function * is called when the __init section is cleaned up \*--------------------------------------------------------------------------------*/ void avm_mtd_cleanup(void) { pr_debug("[%s] entered\n", __func__); #if defined(CONFIG_MTD_UBI) register_mtd_user(&mtd_postinit_notifier_ops); #endif unregister_mtd_user(&mtd_notifier_ops); } subsys_initcall(avm_mtd_init);