#include #include #include #include #include #include #include #if defined(CONFIG_TFFS) #include #include "../../char/tffs/tffs_local.h" #endif #if defined(CONFIG_MTD_UBI) #include #include #endif #include #include struct mtd_info *urlader_mtd __attribute__((weak)); extern int tffs_mtd[]; /* TFFS-MTDs für den TFFS_LGCY-Treiber */ 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 = }; #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]; /* TODO: Remove the arch dependend CONFIG from TFFS and from here! */ #if defined(CONFIG_TFFS_DEV_LEGACY) && TFFS3_VERSION >= TFFS_VERSION(3, 1) && \ defined(CONFIG_ARCH_IPQ807x) static int tffs_mtds_found; #endif #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; } else if (strcmp(mtd->name, "urlader") == 0) { urlader_mtd = mtd; pr_debug("[%s] mtd%d[%s] set urlader_mtd.\n", __func__, mtd->index, mtd->name); #if defined(CONFIG_TFFS) #if defined(CONFIG_TFFS_DEV_LEGACY) } else if (strcmp(mtd->name, "tffs (1)") == 0) { tffs_mtd[0] = mtd->index; #if TFFS_VERSION(3, 1) <= TFFS3_VERSION && defined(CONFIG_ARCH_IPQ807x) tffs_mtds_found |= 1; #endif 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; #if TFFS_VERSION(3, 1) <= TFFS3_VERSION && defined(CONFIG_ARCH_IPQ807x) tffs_mtds_found |= 2; #endif pr_debug("[%s] mtd%d[%s] set tffs mtd 1\n", __func__, mtd->index, mtd->name); #endif } else if(!strcmp(mtd->name, "nand-tffs")) { TFFS3_Register_NAND(mtd); #if TFFS_VERSION(3, 1) <= TFFS3_VERSION && defined(CONFIG_ARCH_IPQ807x) TFFS3_Backend_Ready(); #endif pr_debug("[%s] tffs3 on MTD %s\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(KERN_ERR "{%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); } #if defined(CONFIG_TFFS_DEV_LEGACY) && TFFS_VERSION(3, 1) <= TFFS3_VERSION && \ defined(CONFIG_ARCH_IPQ807x) if (tffs_mtds_found == 3) TFFS3_Backend_Ready(); #endif } 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 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; } extern struct mtd_part_parser avm_mtd_parser; static int __init avm_mtd_init(void) { pr_debug("[%s] entered\n", __func__); register_mtd_parser(&avm_mtd_parser); register_mtd_user(&mtd_notifier_ops); 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); } return 0; } /* this is called from free_initmem as late_initcall is still too early */ void __init 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); deregister_mtd_parser(&avm_mtd_parser); } subsys_initcall(avm_mtd_init);