📄 mphysmap.c
字号:
/* * $Id: mphysmap.c,v 1.2 2005/03/07 23:15:48 joern Exp $ * * Several mappings of NOR chips * * Copyright (c) 2001-2005 J鰎n Engel <joern@wh.fh-wedelde> */#include <linux/kernel.h>#include <linux/module.h>#include <linux/mtd/map.h>#include <linux/mtd/mtd.h>#define NO_DEVICES 8struct map_info maps[NO_DEVICES] = {#if CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH { .name = CONFIG_MTD_MULTI_PHYSMAP_1_NAME, .phys = CONFIG_MTD_MULTI_PHYSMAP_1_START, .size = CONFIG_MTD_MULTI_PHYSMAP_1_LEN, .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH, },#endif#if CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH { .name = CONFIG_MTD_MULTI_PHYSMAP_2_NAME, .phys = CONFIG_MTD_MULTI_PHYSMAP_2_START, .size = CONFIG_MTD_MULTI_PHYSMAP_2_LEN, .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH, },#endif#if CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH { .name = CONFIG_MTD_MULTI_PHYSMAP_3_NAME, .phys = CONFIG_MTD_MULTI_PHYSMAP_3_START, .size = CONFIG_MTD_MULTI_PHYSMAP_3_LEN, .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH, },#endif#if CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH { .name = CONFIG_MTD_MULTI_PHYSMAP_4_NAME, .phys = CONFIG_MTD_MULTI_PHYSMAP_4_START, .size = CONFIG_MTD_MULTI_PHYSMAP_4_LEN, .bankwidth = CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH, },#endif { .name = NULL, },};DECLARE_MUTEX(map_mutex);static int map_one(struct map_info *map){ struct mtd_info *mtd; map->virt = ioremap(map->phys, map->size); if (!map->virt) return -EIO; simple_map_init(map); mtd = do_map_probe("cfi_probe", map); if (!mtd) { iounmap(map->virt); return -ENXIO; } map->map_priv_1 = (unsigned long)mtd; mtd->owner = THIS_MODULE; /* TODO: partitioning */ return add_mtd_device(mtd);}static void unmap_one(struct map_info *map){ struct mtd_info *mtd = (struct mtd_info*)map->map_priv_1; if (map->map_priv_2) kfree(map->name); if (!map->virt) return; BUG_ON(!mtd); BUG_ON(map->map_priv_2 > 1); del_mtd_device(mtd); map_destroy(mtd); iounmap(map->virt); map->map_priv_1 = 0; map->map_priv_2 = 0; map->virt = NULL;}static struct map_info *next_free_map(void){ int i; for (i=0; i<NO_DEVICES; i++) { struct map_info *map = &maps[i]; if (!map->virt) return map; } return NULL;}static int add_one_map(const char *name, unsigned long start, unsigned long len, int width){ struct map_info *map = next_free_map(); if (!map) return -ENOSPC; map->name = kmalloc(strlen(name)+1, GFP_KERNEL); if (!name) return -ENOMEM; strcpy(map->name, name); map->phys = start; map->size = len; map->bankwidth = width; map->map_priv_2 = 1; /* marker to free map->name */ return map_one(map);}static int parse_ulong(unsigned long *num, const char *token){ char *endp; unsigned long n; n = ustrtoul(token, &endp, 0); if (*endp) return -EINVAL; *num = n; return 0;}static int parse_uint(unsigned int *num, const char *token){ char *endp; unsigned long n; n = ustrtoul(token, &endp, 0); if (*endp) return -EINVAL; if ((int)n != n) return -EINVAL; *num = n; return 0;}static int parse_name(char **pname, const char *token, int limit){ size_t len; char *name; len = strlen(token) + 1; if (len > limit) return -ENOSPC; name = kmalloc(len, GFP_KERNEL); if (!name) return -ENOMEM; memcpy(name, token, len); *pname = name; return 0;}static inline void kill_final_newline(char *str){ char *newline = strrchr(str, '\n'); if (newline && !newline[1]) *newline = 0;}#define parse_err(fmt, args...) do { \ printk(KERN_ERR fmt "\n", ## args); \ return 0; \} while(0)/* mphysmap=name,start,len,width */static int mphysmap_setup(const char *val, struct kernel_param *kp){ char buf[64+14+14+14], *str = buf; char *token[4]; char *name; unsigned long start; unsigned long len; unsigned int width; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) parse_err("parameter too long"); strcpy(str, val); kill_final_newline(str); for (i=0; i<4; i++) token[i] = strsep(&str, ","); if (str) parse_err("too many arguments"); if (!token[3]) parse_err("not enough arguments"); ret = parse_name(&name, token[0], 64); if (ret == -ENOMEM) parse_err("out of memory"); if (ret == -ENOSPC) parse_err("name too long"); if (ret) parse_err("illegal name: %d", ret); ret = parse_ulong(&start, token[1]); if (ret) parse_err("illegal start address"); ret = parse_ulong(&len, token[2]); if (ret) parse_err("illegal length"); ret = parse_uint(&width, token[3]); if (ret) parse_err("illegal bus width"); down(&map_mutex); ret = add_one_map(name, start, len, width); up(&map_mutex); if (ret == -ENOSPC) parse_err("no free space for new map"); if (ret) parse_err("error while mapping: %d", ret); return 0;}static int __init mphysmap_init(void){ int i; down(&map_mutex); for (i=0; i<NO_DEVICES; i++) map_one(&maps[i]); up(&map_mutex); return 0;}static void __exit mphysmap_exit(void){ int i; down(&map_mutex); for (i=0; i<NO_DEVICES; i++) unmap_one(&maps[i]); up(&map_mutex);}__module_param_call("", mphysmap, mphysmap_setup, NULL, NULL, 0600);module_init(mphysmap_init);module_exit(mphysmap_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("J鰎n Engel <joern@wh.fh-wedelde>");MODULE_DESCRIPTION("Generic configurable extensible MTD map driver");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -