linux mmc分区_【经验记录】如何给嵌入式Linux的SD/MMC卡驱动中添加多个分区

本文详细记录了在Linux内核驱动中为嵌入式SD/MMC卡添加多个分区的过程。通过分析系统启动后的设备输出信息,确定了在`mmc_bus_probe`和`mmc_blk_probe`中实现分区的关键步骤,并在`drivers/mmc/card/block.c`文件中添加代码来创建和管理分区。通过调试和打印信息,最终定位到`add_partition`函数用于添加分区节点。文章强调了解决问题需要耐心、细心观察和利用现有信息的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

How to add multi partition for SD/MMC card in Linux Driver

之所以写这个,是因为,在这个过程中,自己明显感觉到了,做事情一定要有一定的方法,方法对了,

事情做的才有效率,否则就是事倍功半。

【过程】

当前,Linux下sd/mmc卡的驱动已经实现。需要在此基础上实现,给这个mmc/sd块设备加多个分区。

有人会问,那等系统启动后,通过fdisk工具去分区不也可以吗?回答是,除了我对此fdisk工具不熟悉之外,本身sd/mmc驱动加载后,只有一个区,而我tootfs就是放在sd卡中,然后kernel 通过sd挂载rootfs的,所以,系统启动后,sd卡处于使用中,好像fdisk对于已经使用的sd卡进行分区,估计也会有些问题的。

所以,就需要在驱动加载过程中,加入多个分区。然后我后期向卡的不同的分区去写东西,就很方便了。

言归正传。此处,如果通过NFS启动kernel和rootfs,然后启动后,插入卡,可以显示类似如下信息(4GB的SD卡):

mmc0: new SDHC card at address d555

mmcblk0: mmc0:d555 SD04G 3.79 GiB

mmcblk0: p1

如果里面的分区被破坏,就会这样(这个是1G的SD卡):

mmc0: new high speed SD card at address b368

mmcblk0: mmc0:b368 UD    952 MiB

mmcblk0: unknown partition table

现在要做的,就是对其支持多分区,但是,关于如何对于sd卡里面加多分区,去百度google了,结果是除了这个帖子里:

“Check Setup

After rebooting and inserting a SD card you should have a device file like:

/dev/mmcblk0

And a partition on it:

/dev/mmcblk0p1 ”

让人明白,mmcblk0就是mmc block 0和mmcblk0p1就是mmc block 0 partition 1之外,其他的可以说是一无所获,所以,只能去通过上面的信息,搞清楚到底何时去加的/dev/mmcblk0p1,然后在对应的地方

加上自己要的多分区。

不过,具体是什么地方输出这些信息的,自己去mmc驱动里面,一直无法找到。而且mmc驱动只是针对host controller而言的,而这些信息输出是在卡插上的时候,识别了卡的之后,才能显示具体信息的。

不过,在mmc驱动至少能知道,大概信息,就是在这些函数里面:

mmc_rescan -> mmc_attach_sd - -> mmc_add_card() ->device_add() ->

然后在device_add里面,太多相关的系统函数kobject_add,blocking_notifier_call_chain,device_create_file,device_create_file,device_create_sys_dev_entry,device_add_class_symlinks,device_add_attrs,bus_add_device,device_pm_add,bus_attach_device,。。。。。

所以,实现没法搞清楚,具体是哪个函数具体去实现的底层加了/dev/mmcblk0p1这个节点的。

继续debug,加打印信息,在插入卡后,出现:

# mmc0: new SDHC card at address d555

--SD-- 1

--SD-- 2

--SD-- 3

--SD-- 4

--SD-- 6

--SD-- 7

--SD-- 8

--SD-- 1

--SD-- 9

--SD-- 1

--SD-- 10

mmcblk0: mmc0:d555 SD04G 3.79 GiB

--SD-- 1

--SD-- 2

--SD-- 3

--SD-- 4

--SD-- 5

--SD-- 6

--SD-- 7

--SD-- 8

--SD-- 1

--SD-- 9

--SD-- 1

--SD-- 10

--SD-- 11

--SD-- 12

mmcblk0: p1

--SD-- 1

--SD-- 2

--SD-- 3

--SD-- 4

--SD-- 5

--SD-- 6

--SD-- 7

--SD-- 8

--SD-- 1

--SD-- 9

--SD-- 1

--SD-- 10

--SD-- 11

--SD-- 12

--SD-- 1

--SD-- 2

--SD-- 3

--SD-- 4

--SD-- 6

--SD-- 7

--SD-- 8

--SD-- 1

--SD-- 9

--SD-- 1

--SD-- 10

--SD-- 11

--SD-- 12

--SD-- 11

--SD-- 12

所以,由:

--SD-- 10

mmcblk0: mmc0:d555 SD04G 3.79 GiB

判断是

bus_attach_device(dev);

if (parent)

klist_add_tail(&dev->knode_parent, &parent->klist_children);

去实现的/dev/mmcblk0p1,但是去看了这bus_attach_device和klist_add_tail,也仍然是看不懂具体,不知道哪里去具体实现的。

不过,在看代码过程中,发现 kobject_uevent(&dev->kobj, KOBJ_ADD);

中有个dev->kobj,这个kobj是驱动的一个核心数据结构,其中有个name变量,所以,就想,打印这些kobj的name看看,都是哪些名称所以去掉其他打印,加上这个:

printk("--SD-- 10, obj_name:%s\n", dev->kobj.name);

然后debug结果输出是:

# mmc0: new SDHC card at address d555

--SD-- 1

--SD-- 10, obj_name:mmc0:d555

mmcblk0: mmc0:d555 SD04G 3.79 GiB

--SD-- 1

--SD-- 10, obj_name:mmcblk0

--SD-- 11

--SD-- 12

mmcblk0: p1

--SD-- 1

--SD-- 10, obj_name:mmcblk0p1

--SD-- 11

--SD-- 12

--SD-- 1

--SD-- 10, obj_name:179:0

--SD-- 11

--SD-- 12

--SD-- 11

--SD-- 12

因此,知道了mmcblk0p1是从这里:

mmcblk0: p1

--SD-- 1

--SD-- 10, obj_name:mmcblk0p1

实现的,但是仍旧不知道是哪些函数调用到这里的device_add,

此时,由于以前遇到过,dump_stack()函数,知道这个函数可以打印堆栈信息,也就是当前栈上的函数调用信息,所以,此时可以派上用场了。同时,也知道“179:0”是mmc的主次设备号,所以继续debug,加上这些:

if((0==strcmp("mmcblk0p1", dev->kobj.name)) ||

(0==strcmp("mmcblk0", dev->kobj.name)) ||

(0==strcmp("179:0", dev->kobj.name)) ||

(0==strcmp("179:1", dev->kobj.name)) )

{

printk("--SD-- 10, obj_name:%s\n", dev->kobj.name);

dump_stack();

}

最后打印出来我想要的函数调用信息:

# mmc0: new SDHC card at address d555

mmcblk0: mmc0:d555 SD04G 3.79 GiB

--SD-- 10, obj_name:mmcblk0

[] (dump_stack+0x0/0x14) from [] (device_add+0x4c4/0x688)

[] (device_add+0x0/0x688) from [] (register_disk+0x5c/0x154)

[] (register_disk+0x0/0x154) from [] (add_disk+0xe8/0x150)

r7:00000000 r6:c3987200 r5:c3987a00 r4:c388ddde

[] (add_disk+0x0/0x150) from [] (mmc_blk_probe+0x224/0x2ec)

r5:c3a9a120 r4:c388ddde

[] (mmc_blk_probe+0x0/0x2ec) from [] (mmc_bus_probe+0x20/0x24)

[] (mmc_bus_probe+0x0/0x24) from [] (driver_probe_device+0xa8/0x1bc)

[] (driver_probe_device+0x0/0x1bc) from [] (__device_attach+0x10/0x14)

[] (__device_attach+0x0/0x14) from [] (bus_for_each_drv+0x68/0x94)

[] (bus_for_each_drv+0x0/0x94) from [] (device_attach+0x64/0x7c)

r7:c3987290 r6:c3a5ef60 r5:c39872b0 r4:c3987204

[] (device_attach+0x0/0x7c) from [] (bus_attach_device+0x40/0x60)

r5:c3987204 r4:c031c274

[] (bus_attach_device+0x0/0x60) from [] (device_add+0x4cc/0x688)

r5:c3987204 r4:00000000

[] (device_add+0x0/0x688) from [] (mmc_add_card+0x88/0x134)

[] (mmc_add_card+0x0/0x134) from [] (mmc_attach_sd+0x15c/0x858)

r5:00000000 r4:c3bfb960

[] (mmc_attach_sd+0x0/0x858) from [] (mmc_rescan+0x228/0x29c)

[] (mmc_rescan+0x0/0x29c) from [] (run_workqueue+0xe8/0x198)

r6:c388c000 r5:c019f3e8 r4:c3885720

[] (run_workqueue+0x0/0x198) from [] (worker_thread+0x5c/0xb8)

r7:c03291d0 r6:c388dfa8 r5:c3885728 r4:c3885720

[] (worker_thread+0x0/0xb8) from [] (kthread+0x58/0x8c)

r6:c0048a6c r5:c3885720 r4:c388c000

[] (kthread+0x0/0x8c) from [] (do_exit+0x0/0x738)

r7:00000000 r6:00000000 r5:00000000 r4:00000000

mmcblk0: p1

--SD-- 10, obj_name:mmcblk0p1

[] (dump_stack+0x0/0x14) from [] (device_add+0x4c4/0x688)

[] (device_add+0x0/0x688) from [] (add_partition+0x11c/0x21c)

[] (add_partition+0x0/0x21c) from [] (rescan_partitions+0x234/0x338)

[] (rescan_partitions+0x0/0x338) from [] (__blkdev_get+0x15c/0x2a8)

[] (__blkdev_get+0x0/0x2a8) from [] (blkdev_get+0x14/0x18)

[] (blkdev_get+0x0/0x18) from [] (register_disk+0x134/0x154)

[] (register_disk+0x0/0x154) from [] (add_disk+0xe8/0x150)

r7:00000000 r6:c3987200 r5:c3987a00 r4:c388ddde

[] (add_disk+0x0/0x150) from [] (mmc_blk_probe+0x224/0x2ec)

r5:c3a9a120 r4:c388ddde

[] (mmc_blk_probe+0x0/0x2ec) from [] (mmc_bus_probe+0x20/0x24)

[] (mmc_bus_probe+0x0/0x24) from [] (driver_probe_device+0xa8/0x1bc)

[] (driver_probe_device+0x0/0x1bc) from [] (__device_attach+0x10/0x14)

[] (__device_attach+0x0/0x14) from [] (bus_for_each_drv+0x68/0x94)

[] (bus_for_each_drv+0x0/0x94) from [] (device_attach+0x64/0x7c)

r7:c3987290 r6:c3a5ef60 r5:c39872b0 r4:c3987204

[] (device_attach+0x0/0x7c) from [] (bus_attach_device+0x40/0x60)

r5:c3987204 r4:c031c274

[] (bus_attach_device+0x0/0x60) from [] (device_add+0x4cc/0x688)

r5:c3987204 r4:00000000

[] (device_add+0x0/0x688) from [] (mmc_add_card+0x88/0x134)

[] (mmc_add_card+0x0/0x134) from [] (mmc_attach_sd+0x15c/0x858)

r5:00000000 r4:c3bfb960

[] (mmc_attach_sd+0x0/0x858) from [] (mmc_rescan+0x228/0x29c)

[] (mmc_rescan+0x0/0x29c) from [] (run_workqueue+0xe8/0x198)

r6:c388c000 r5:c019f3e8 r4:c3885720

[] (run_workqueue+0x0/0x198) from [] (worker_thread+0x5c/0xb8)

r7:c03291d0 r6:c388dfa8 r5:c3885728 r4:c3885720

[] (worker_thread+0x0/0xb8) from [] (kthread+0x58/0x8c)

r6:c0048a6c r5:c3885720 r4:c388c000

[] (kthread+0x0/0x8c) from [] (do_exit+0x0/0x738)

r7:00000000 r6:00000000 r5:00000000 r4:00000000

--SD-- 10, obj_name:179:0

[] (dump_stack+0x0/0x14) from [] (device_add+0x4c4/0x688)

[] (device_add+0x0/0x688) from [] (device_register+0x1c/0x20)

[] (device_register+0x0/0x20) from [] (device_create_vargs+0x90/0xac)

r4:c3a79400

[] (device_create_vargs+0x0/0xac) from [] (bdi_register+0x54/0xac)

r8:00000176 r7:00000000 r6:c3987200 r5:00000000 r4:c39ba204

[] (bdi_register+0x0/0xac) from [] (bdi_register_dev+0x2c/0x34)

r3:000000b3 r2:c02c0f24

r5:c3987a00 r4:c39ba168

[] (bdi_register_dev+0x0/0x34) from [] (add_disk+0x100/0x150)

[] (add_disk+0x0/0x150) from [] (mmc_blk_probe+0x224/0x2ec)

r5:c3a9a120 r4:c388ddde

[] (mmc_blk_probe+0x0/0x2ec) from [] (mmc_bus_probe+0x20/0x24)

[] (mmc_bus_probe+0x0/0x24) from [] (driver_probe_device+0xa8/0x1bc)

[] (driver_probe_device+0x0/0x1bc) from [] (__device_attach+0x10/0x14)

[] (__device_attach+0x0/0x14) from [] (bus_for_each_drv+0x68/0x94)

[] (bus_for_each_drv+0x0/0x94) from [] (device_attach+0x64/0x7c)

r7:c3987290 r6:c3a5ef60 r5:c39872b0 r4:c3987204

[] (device_attach+0x0/0x7c) from [] (bus_attach_device+0x40/0x60)

r5:c3987204 r4:c031c274

[] (bus_attach_device+0x0/0x60) from [] (device_add+0x4cc/0x688)

r5:c3987204 r4:00000000

[] (device_add+0x0/0x688) from [] (mmc_add_card+0x88/0x134)

[] (mmc_add_card+0x0/0x134) from [] (mmc_attach_sd+0x15c/0x858)

r5:00000000 r4:c3bfb960

[] (mmc_attach_sd+0x0/0x858) from [] (mmc_rescan+0x228/0x29c)

[] (mmc_rescan+0x0/0x29c) from [] (run_workqueue+0xe8/0x198)

r6:c388c000 r5:c019f3e8 r4:c3885720

[] (run_workqueue+0x0/0x198) from [] (worker_thread+0x5c/0xb8)

r7:c03291d0 r6:c388dfa8 r5:c3885728 r4:c3885720

[] (worker_thread+0x0/0xb8) from [] (kthread+0x58/0x8c)

r6:c0048a6c r5:c3885720 r4:c388c000

[] (kthread+0x0/0x8c) from [] (do_exit+0x0/0x738)

r7:00000000 r6:00000000 r5:00000000 r4:00000000

从上面可以看出:mmc_bus_probe ->mmc_blk_probe->add_disk,就是具体实现分区的地方了。

知道哪些函数了,剩下的找到对应C文件。

本来觉得很简单的,去百度一下mmc_blk_probe应该就能找到对应C文件。结果百度找的是drivers/mmc/mmc_block.c,但是,我去我的2.6.28的kernel,发现没有这个文件,所以很是无语,只能继续找。。。

最后,在drivers/mmc/card/block.c中找到了这些相关的函数:

mmc_blk_probe,add_disk,其中,“mmcblk0: mmc0:d555 SD04G 3.79 GiB ”就是mmc_blk_probe中的

printk(KERN_INFO "%s: %s %s %s %s\n",

md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),

cap_str, md->read_only ? "(ro)" : "");

打印的。

找到这里,要做的事情,其实才刚开始,但是也是只是时间问题了。因为我之前自己做了LBA的块设备,所以,知道怎么添加多分区。此处,只是要添加一些代码即可。

【具体代码】

在drivers/mmc/card/block.c添加如下代码:

#define AS353X_MMC_SUPPORT_MULTI_PART 1

#if AS353X_MMC_SUPPORT_MULTI_PART

typedef struct

{

int32_t start_sec;

int32_t sec_num;

}as353x_blk_part_info;

/*

PatitionName FsType    PartitionSize       Rage(From-To)

(1)uImage None   (4M)         0      - (4M)

(2)Rootfs FAT/Ext2   (28M or 124M)       (4M)     - (32M or 128M)

(3)Data    Ext2/Ext3 (CardSize -496KB - (28M or 124M)) (32M or 128M) - (CardSize -496KB)

(4)uboot   None   (496KB)        (CardSize -496KB) - (CardSize )

A.not support multi partitions for <=32MB, it is too small for rootfs+uImage+uboot

B.for rootfs, if mmc/sd size > 128MB, reserved 128MB, or reserved 32MB

C.for uboot, 496KB = 0x7C000, which if fixed by BootCode

*/

#ifndef SZ_1M

#define SZ_1M                           0x00100000

#endif

#ifndef SZ_1K

#define SZ_1K                           0x00000400

#endif

#define SDMMC_BLOCK_SIZE 512

#define SDMMC_CARDSIZE_128MB     (128 *SZ_1M)

#define SDMMC_CARDSIZE_TOO_SMALL (32 *SZ_1M)

#define SDMMC_ROOTFS_SIZE_128MB    (128*SZ_1M) /* actual is 128-4=124MB*/

#define SDMMC_ROOTFS_SIZE_32MB    (32*SZ_1M)   /* actual is 32-4= 28MB*/

#define SDMMC_KERNEL_SIZE      (4*SZ_1M)

#define SDMMC_UBOOT_SIZE      (496*SZ_1K)    /* 0x7C000=496KB */

#define SDMMC_ROOTFS_128MB_BLK_NUM (SDMMC_ROOTFS_SIZE_128MB/SDMMC_BLOCK_SIZE)

#define SDMMC_ROOTFS_32MB_BLK_NUM (SDMMC_ROOTFS_SIZE_32MB/SDMMC_BLOCK_SIZE)

#define SDMMC_KERNEL_BLK_NUM     (SDMMC_KERNEL_SIZE/SDMMC_BLOCK_SIZE)

#define SDMMC_UBOOT_BLK_NUM     (SDMMC_UBOOT_SIZE/SDMMC_BLOCK_SIZE)

/* 0 is the first partion for whole disk */

#define AS353X_SDMMC_MAX_PARTITIONS   5

static as353x_blk_part_info as353x_mmc_partitions[AS353X_SDMMC_MAX_PARTITIONS];

/* 1 block=512B */

static int as353x_init_sdmmc_parition(uint32_t card_size_in_blocks)

{

uint32_t rootfs_blocks;

uint64_t card_size_bytes = card_size_in_blocks * SDMMC_BLOCK_SIZE;

if(card_size_bytes <= SDMMC_CARDSIZE_TOO_SMALL)

return -1; /* not support multi partitions here */

/* 0 is for whole disk, not used here */

as353x_mmc_partitions[0].start_sec = 0;

as353x_mmc_partitions[0].sec_num =0;

if(card_size_bytes > SDMMC_CARDSIZE_128MB)

{

/* > 128MB, is 128MB */

rootfs_blocks = SDMMC_ROOTFS_128MB_BLK_NUM;

}

else

{

/* <=128MB is 32MB */

rootfs_blocks = SDMMC_ROOTFS_32MB_BLK_NUM;

}

/* 4M uImage */

as353x_mmc_partitions[1].start_sec = 0;

as353x_mmc_partitions[1].sec_num =SDMMC_KERNEL_BLK_NUM;

/* 28 or 124 MB rootfs */

as353x_mmc_partitions[2].start_sec = SDMMC_KERNEL_BLK_NUM;

as353x_mmc_partitions[2].sec_num = rootfs_blocks - SDMMC_KERNEL_BLK_NUM;

/* carsize - 496KB- (28 or 124) MB */

as353x_mmc_partitions[3].start_sec = rootfs_blocks;

as353x_mmc_partitions[3].sec_num = card_size_in_blocks - rootfs_blocks - SDMMC_UBOOT_BLK_NUM;

/* 496KB uboot */

as353x_mmc_partitions[4].start_sec = card_size_in_blocks - SDMMC_UBOOT_BLK_NUM;

as353x_mmc_partitions[4].sec_num = SDMMC_UBOOT_BLK_NUM;

return 0;

}

#endif

static int mmc_blk_probe(struct mmc_card *card)

{

。。。。。

char cap_str[10];

#if AS353X_MMC_SUPPORT_MULTI_PART

int i;

struct hd_struct * hd;

#endif

/*

* Check that the card supports the command class(es) we need.

*/

if (!(card->csd.cmdclass & CCC_BLOCK_READ))

return -ENODEV;

。。。。。。

mmc_set_drvdata(card, md);

add_disk(md->disk);

#if AS353X_MMC_SUPPORT_MULTI_PART

if(0==as353x_init_sdmmc_parition(get_capacity(md->disk)))

{

for(i = 1; i < AS353X_SDMMC_MAX_PARTITIONS; i++)

{

hd = add_partition(md->disk, i, as353x_mmc_partitions[i].start_sec, as353x_mmc_partitions[i].sec_num, ADDPART_FLAG_NONE);

}

}

#endif

return 0;

。。。。

}

【总结】

1.还是应了那句话,只要有源码,就不怕解决不了问题。

2.调试的时候,很多时候是看起来没有办法了,但是只要细心,额外看到的信息,可以充分利用,比如上面的dev->kobj有个name参数,就可以拿来打印出来看看到底是哪些名字,以便可能继续提供更多的信息,便于找到新的办法或线索。

3.做事情,还是要有耐力和找到有效的办法,没有办法,也要尽可能地想办法。如果具备了一定的基础知识,加上细心观察,充分利用信息,很多时候,即使

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值