mtd分区创建linux,浅析linux下mtd设备onenand存储器的分区和节点创建流程及yaffs2文件系统挂载...

浅析linux下mtd设备onenand存储器的分区和节点创建流程及yaffs2文件系统挂载

在arch/arm/mach-pxa/luther.c这个产品平台文件中,即:

MACHINE_START(LUTHER, "luther")

.phys_io = 0x40000000,

.boot_params = 0xa0000100,

.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,

.map_io = pxa_map_io,

.init_irq = pxa3xx_init_irq,

.timer = &pxa_timer,

.init_machine = luther_init,

MACHINE_END

=>luther_init

=>luther_init_onenand

=>luther_onenand_info.parts = android_256m_v75_partitions;

=>luther_onenand_info.nr_parts = ARRAY_SIZE(android_256m_v75_partitions);

=>pxa3xx_device_onenand.dev.platform_data = &luther_onenand_info;

=>platform_device_register(&pxa3xx_device_onenand);

//flash设备结构体定义如下

static struct mtd_partition android_256m_v75_partitions[] = {

[0] = {

.name = "Bootloader",

.offset = 0,

.size = 0x100000,

.mask_flags = MTD_WRITEABLE, /* force read-only */

},

...

[3] = {

.name = "logo",

.offset = 0xa00000,

.size = 0x040000,

.mask_flags = MTD_WRITEABLE, /* force read-only */

},

[4] = {

.name = "Kernel",

.offset = 0xa40000,

.size = 0x300000,

.mask_flags = MTD_WRITEABLE, /* force read-only */

},

[5] = {

.name = "system",

.offset = 0x0d40000,

.size = 0x6000000, /* mount 96M fs */

},

...

};

struct platform_device pxa3xx_device_onenand = {

.name        = "onenand",

.id        = -1,

.dev        = {

.dma_mask    = &pxa3xx_onenand_dma_mask,

.coherent_dma_mask = DMA_BIT_MASK(32),

},

.resource    = pxa3xx_resources_onenand,

.num_resources    = ARRAY_SIZE(pxa3xx_resources_onenand),

};

static struct flash_platform_data luther_onenand_info;

static void __init luther_init_onenand(void)

{

if (is_android()) {

luther_onenand_info.parts = android_256m_v75_partitions;

luther_onenand_info.nr_parts =

ARRAY_SIZE(android_256m_v75_partitions);

} else {

luther_onenand_info.parts = pxa930_256m_v75_partitions;

luther_onenand_info.nr_parts =

ARRAY_SIZE(pxa930_256m_v75_partitions);

}

pxa3xx_device_onenand.dev.platform_data = &luther_onenand_info;

platform_device_register(&pxa3xx_device_onenand);

}

//flash驱动定义如下

drivers\mtd\onenand\generic.c

#define DRIVER_NAME    "onenand"

static struct platform_driver generic_onenand_driver = {

.driver = {

.name    = DRIVER_NAME,

},

.probe        = generic_onenand_probe,

.remove        = generic_onenand_remove,

#ifdef CONFIG_PM

.suspend    = NULL,

.resume        = NULL,

#endif

};

static int __devinit generic_onenand_probe(struct platform_device *dev)

{

struct onenand_info *info;

struct platform_device *pdev = dev;//这里pdev就是pxa3xx_device_onenand

struct flash_platform_data *pdata = pdev->dev.platform_data;//这里pdata就是luther_onenand_info

struct resource *res = pdev->resource;

unsigned long size = res->end - res->start + 1;

int err;

info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);//申请该onenand chip对应的描述结构体,包含操作onenand的读写函数

if (!info)

return -ENOMEM;

if (!request_mem_region(res->start, size, pdev->name)) {

err = -EBUSY;

goto out_free_info;

}

info->onenand.base = ioremap(res->start, size);

if (!info->onenand.base) {

err = -ENOMEM;

goto out_release_mem_region;

}

info->onenand.mmcontrol = pdata->mmcontrol;

info->onenand.irq = platform_get_irq(pdev, 0);

info->mtd.name = pdev->dev.bus_id;//为"onenand"

//这就要参看platform_device_register(&pxa3xx_device_onenand);了

//dev->kobj.kset = devices_kset;这个platform_device对应devices_kset管理集

//platform_device_add=>

//if (pdev->id != -1) snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, pdev->id);//指定了id索引值

//else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);//如果id=-1,那么为"onenand"

info->mtd.priv = &info->onenand;//由kzalloc申请的结构体info

info->mtd.owner = THIS_MODULE;

if (onenand_scan(&info->mtd, 1)) {//1个chip

err = -ENXIO;

goto out_iounmap;

}

#ifdef CONFIG_MTD_PARTITIONS

err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);

//#ifdef CONFIG_MTD_PARTITIONS

//static const char *part_probes[] = { "cmdlinepart", NULL, };

//#endif

//parse_mtd_partitions=>get_partition_parser

//register_mtd_parser注册struct mtd_part_parser方法集到该链表

if (err > 0)

add_mtd_partitions(&info->mtd, info->parts, err);

//add_mtd_partitions=>add_mtd_device//register_mtd_user注册struct mtd_notifier方法集到该链表    else if (err < 0 && pdata->parts)

add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);

else

#endif

err = add_mtd_device(&info->mtd);

dev_set_drvdata(&pdev->dev, info);

return 0;

out_iounmap:

iounmap(info->onenand.base);

out_release_mem_region:

release_mem_region(res->start, size);

out_free_info:

kfree(info);

return err;

}

int add_mtd_partitions(struct mtd_info *master,

const struct mtd_partition *parts,

int nbparts)

{

...

for (i = 0; i < nbparts; i++) {

slave = kzalloc (sizeof(*slave), GFP_KERNEL);

list_add(&slave->list, &mtd_partitions);//添加到mtd_partitions链表中        slave->mtd.flags = master->flags & ~parts[i].mask_flags;

slave->mtd.size = parts[i].size;

slave->mtd.name = parts[i].name;

slave->offset = parts[i].offset;

slave->index = i;

...添加操作slave的onenand存储器读写函数

add_mtd_device(&slave->mtd);//向sysfs文件系统添加该mtd分区设备        slave->registered = 1;

}

return 0;

}

int add_mtd_device(struct mtd_info *mtd)

{

int i;

BUG_ON(mtd->writesize == 0);

mutex_lock(&mtd_table_mutex);

for (i=0; i < MAX_MTD_DEVICES; i++)

if (!mtd_table[i]) {//从mtd_table中找一个空位置            struct list_head *this;

mtd_table[i] = mtd;

//将该磁盘分区添加到mtd_table[i]数组中,该mtd_table[i]数组中的内容将在/proc/mtd属性文件的读方法mtd_read_proc=>mtd_proc_info中组织内容给用户空间[luther.gliethttp]            mtd->index = i;

mtd->usecount = 0;

/* Some chips always power up locked. Unlock them now */

if ((mtd->flags & MTD_WRITEABLE)

&& (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {

if (mtd->unlock(mtd, 0, mtd->size))

printk(KERN_WARNING

"%s: unlock failed, "

"writes may not work\n",

mtd->name);

}

DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);

/* No need to get a refcount on the module containing

the notifier, since we hold the mtd_table_mutex */

list_for_each(this, &mtd_notifiers) {

struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);

not->add(mtd);//调用mtd_notify_add函数向sysfs文件系统注册登记该该mtd分区[luther.gliethttp]//这里就是在/dev/mtd/目录下创建mtd0,mtd1,...等char类型文件节点[luther.gliethttp]//init_mtdchar=>//register_mtd_user(&notifier);            }

mutex_unlock(&mtd_table_mutex);

/* We _know_ we aren't being removed, because

our caller is still holding us here. So none

of this try_ nonsense, and no bitching about it

either. :) */

__module_get(THIS_MODULE);

return 0;

}

mutex_unlock(&mtd_table_mutex);

return 1;

}

module_init(init_mtdchar);

static int __init init_mtdchar(void)

{

if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {

printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",

MTD_CHAR_MAJOR);

return -EAGAIN;

}

mtd_class = class_create(THIS_MODULE, "mtd");//创建/sys/class/mtd类目录

if (IS_ERR(mtd_class)) {

printk(KERN_ERR "Error creating mtd class.\n");

unregister_chrdev(MTD_CHAR_MAJOR, "mtd");

return PTR_ERR(mtd_class);

}

register_mtd_user(&notifier);

return 0;

}

#define MTD_CHAR_MAJOR 90

static void mtd_notify_add(struct mtd_info* mtd)

{

if (!mtd)

return;

//发送/class/mtd/mtd0,...之类的netlink到init用户进程[luther.gliethttp]    device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index);

device_create(mtd_class, NULL,

MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index);

}

static void mtd_notify_remove(struct mtd_info* mtd)

{

if (!mtd)

return;

device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));

device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));

}

static struct mtd_notifier notifier = {

.add = mtd_notify_add,

.remove = mtd_notify_remove,

};

//在init进程中main

=>handle_device_fd

=>handle_device_event

=>

static void handle_device_event(struct uevent *uevent)

{

...

if(!strncmp(uevent->path, "/class/mtd/", 11)) {//重定向该uevent路径到"/dev/mtd/"目录[luther.gliethttp]        base = "/dev/mtd/";

mkdir(base, 0755);

} else if(!strncmp(uevent->path, "/class/misc/", 12) &&

!strncmp(name, "log_", 4)) {

base = "/dev/log/";

mkdir(base, 0755);

name += 4;

}

...

snprintf(devpath, sizeof(devpath), "%s%s", base, name);

if(!strcmp(uevent->action, "add")) {

make_device(devpath, block, uevent->major, uevent->minor);

return;

}

if(!strcmp(uevent->action, "remove")) {

unlink(devpath);

return;

}

}

那么onenand的分区磁盘已经由init进程根据uevent信息,在/dev/mtd/目录下创建了char类型的文件节点,那么接下来就是,如何将磁盘mount到我们指定的文件系统了,

该操作当然是在init.rc中系统启动时自动完成的了,让我们来看看[luther.gliethttp]

首先来看看mtd设备在/proc文件系统的属性文件/proc/mtd的读方法实现[luther.gliethttp]:

static inline int mtd_proc_info (char *buf, int i)

{

struct mtd_info *this = mtd_table[i];//打印add_mtd_device=>mtd_table[i] = mtd;添加的相应分区磁盘信息[luther.gliethttp]

if (!this)

return 0;

return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size,

this->erasesize, this->name);

}

static int mtd_read_proc (char *page, char **start, off_t off, int count,

int *eof, void *data_unused)

{

int len, l, i;

off_t begin = 0;

mutex_lock(&mtd_table_mutex);

len = sprintf(page, "dev: size erasesize name\n");

for (i=0; i< MAX_MTD_DEVICES; i++) {

l = mtd_proc_info(page + len, i);

len += l;

if (len+begin > off+count)

goto done;

if (len+begin < off) {

begin += len;

len = 0;

}

}

*eof = 1;

done:

mutex_unlock(&mtd_table_mutex);

if (off >= len+begin)

return 0;

*start = page + (off-begin);

return ((count < begin+len-off) ? count : begin+len-off);

}

/*====================================================================*/

/* Init code */

static int __init init_mtd(void)

{

if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))//创建/proc/mtd属性文件[luther.gliethttp]        proc_mtd->read_proc = mtd_read_proc;//该属性的读操作方法    return 0;

}

module_init(init_mtd);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值