zoukankan      html  css  js  c++  java
  • 【经验记录】如何给嵌入式Linux的SD/MMC卡驱动中添加多个分区

    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了,结果是除了这个帖子里:

    http://en.gentoo-wiki.com/wiki/SD_and_MMC_card_readers

    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
    [<c025deac>] (dump_stack+0x0/0x14) from [<c0184cd8>] (device_add+0x4c4/0x688)
    [<c0184814>] (device_add+0x0/0x688) from [<c00c9360>] (register_disk+0x5c/0x154)
    [<c00c9304>] (register_disk+0x0/0x154) from [<c013a204>] (add_disk+0xe8/0x150)
    r7:00000000 r6:c3987200 r5:c3987a00 r4:c388ddde
    [<c013a11c>] (add_disk+0x0/0x150) from [<c01a4f54>] (mmc_blk_probe+0x224/0x2ec)
    r5:c3a9a120 r4:c388ddde
    [<c01a4d30>] (mmc_blk_probe+0x0/0x2ec) from [<c019f868>] (mmc_bus_probe+0x20/0x24)
    [<c019f848>] (mmc_bus_probe+0x0/0x24) from [<c0186eb0>] (driver_probe_device+0xa8/0x1bc)
    [<c0186e08>] (driver_probe_device+0x0/0x1bc) from [<c0187064>] (__device_attach+0x10/0x14)
    [<c0187054>] (__device_attach+0x0/0x14) from [<c0186448>] (bus_for_each_drv+0x68/0x94)
    [<c01863e0>] (bus_for_each_drv+0x0/0x94) from [<c01870f8>] (device_attach+0x64/0x7c)
    r7:c3987290 r6:c3a5ef60 r5:c39872b0 r4:c3987204
    [<c0187094>] (device_attach+0x0/0x7c) from [<c0186224>] (bus_attach_device+0x40/0x60)
    r5:c3987204 r4:c031c274
    [<c01861e4>] (bus_attach_device+0x0/0x60) from [<c0184ce0>] (device_add+0x4cc/0x688)
    r5:c3987204 r4:00000000
    [<c0184814>] (device_add+0x0/0x688) from [<c019fa00>] (mmc_add_card+0x88/0x134)
    [<c019f978>] (mmc_add_card+0x0/0x134) from [<c01a1548>] (mmc_attach_sd+0x15c/0x858)
    r5:00000000 r4:c3bfb960
    [<c01a13ec>] (mmc_attach_sd+0x0/0x858) from [<c019f610>] (mmc_rescan+0x228/0x29c)
    [<c019f3e8>] (mmc_rescan+0x0/0x29c) from [<c004842c>] (run_workqueue+0xe8/0x198)
    r6:c388c000 r5:c019f3e8 r4:c3885720
    [<c0048344>] (run_workqueue+0x0/0x198) from [<c0048ac8>] (worker_thread+0x5c/0xb8)
    r7:c03291d0 r6:c388dfa8 r5:c3885728 r4:c3885720
    [<c0048a6c>] (worker_thread+0x0/0xb8) from [<c004c428>] (kthread+0x58/0x8c)
    r6:c0048a6c r5:c3885720 r4:c388c000
    [<c004c3d0>] (kthread+0x0/0x8c) from [<c003abec>] (do_exit+0x0/0x738)
    r7:00000000 r6:00000000 r5:00000000 r4:00000000

    mmcblk0: p1
    --SD-- 10, obj_name:mmcblk0p1
    [<c025deac>] (dump_stack+0x0/0x14) from [<c0184cd8>] (device_add+0x4c4/0x688)
    [<c0184814>] (device_add+0x0/0x688) from [<c00c9648>] (add_partition+0x11c/0x21c)
    [<c00c952c>] (add_partition+0x0/0x21c) from [<c00c9ad0>] (rescan_partitions+0x234/0x338)
    [<c00c989c>] (rescan_partitions+0x0/0x338) from [<c00aee3c>] (__blkdev_get+0x15c/0x2a8)
    [<c00aece0>] (__blkdev_get+0x0/0x2a8) from [<c00aef9c>] (blkdev_get+0x14/0x18)
    [<c00aef88>] (blkdev_get+0x0/0x18) from [<c00c9438>] (register_disk+0x134/0x154)
    [<c00c9304>] (register_disk+0x0/0x154) from [<c013a204>] (add_disk+0xe8/0x150)
    r7:00000000 r6:c3987200 r5:c3987a00 r4:c388ddde
    [<c013a11c>] (add_disk+0x0/0x150) from [<c01a4f54>] (mmc_blk_probe+0x224/0x2ec)
    r5:c3a9a120 r4:c388ddde
    [<c01a4d30>] (mmc_blk_probe+0x0/0x2ec) from [<c019f868>] (mmc_bus_probe+0x20/0x24)
    [<c019f848>] (mmc_bus_probe+0x0/0x24) from [<c0186eb0>] (driver_probe_device+0xa8/0x1bc)
    [<c0186e08>] (driver_probe_device+0x0/0x1bc) from [<c0187064>] (__device_attach+0x10/0x14)
    [<c0187054>] (__device_attach+0x0/0x14) from [<c0186448>] (bus_for_each_drv+0x68/0x94)
    [<c01863e0>] (bus_for_each_drv+0x0/0x94) from [<c01870f8>] (device_attach+0x64/0x7c)
    r7:c3987290 r6:c3a5ef60 r5:c39872b0 r4:c3987204
    [<c0187094>] (device_attach+0x0/0x7c) from [<c0186224>] (bus_attach_device+0x40/0x60)
    r5:c3987204 r4:c031c274
    [<c01861e4>] (bus_attach_device+0x0/0x60) from [<c0184ce0>] (device_add+0x4cc/0x688)
    r5:c3987204 r4:00000000
    [<c0184814>] (device_add+0x0/0x688) from [<c019fa00>] (mmc_add_card+0x88/0x134)
    [<c019f978>] (mmc_add_card+0x0/0x134) from [<c01a1548>] (mmc_attach_sd+0x15c/0x858)
    r5:00000000 r4:c3bfb960
    [<c01a13ec>] (mmc_attach_sd+0x0/0x858) from [<c019f610>] (mmc_rescan+0x228/0x29c)
    [<c019f3e8>] (mmc_rescan+0x0/0x29c) from [<c004842c>] (run_workqueue+0xe8/0x198)
    r6:c388c000 r5:c019f3e8 r4:c3885720
    [<c0048344>] (run_workqueue+0x0/0x198) from [<c0048ac8>] (worker_thread+0x5c/0xb8)
    r7:c03291d0 r6:c388dfa8 r5:c3885728 r4:c3885720
    [<c0048a6c>] (worker_thread+0x0/0xb8) from [<c004c428>] (kthread+0x58/0x8c)
    r6:c0048a6c r5:c3885720 r4:c388c000
    [<c004c3d0>] (kthread+0x0/0x8c) from [<c003abec>] (do_exit+0x0/0x738)
    r7:00000000 r6:00000000 r5:00000000 r4:00000000

    --SD-- 10, obj_name:179:0
    [<c025deac>] (dump_stack+0x0/0x14) from [<c0184cd8>] (device_add+0x4c4/0x688)
    [<c0184814>] (device_add+0x0/0x688) from [<c0184eb8>] (device_register+0x1c/0x20)
    [<c0184e9c>] (device_register+0x0/0x20) from [<c0184f4c>] (device_create_vargs+0x90/0xac)
    r4:c3a79400
    [<c0184ebc>] (device_create_vargs+0x0/0xac) from [<c00702a0>] (bdi_register+0x54/0xac)
    r8:00000176 r7:00000000 r6:c3987200 r5:00000000 r4:c39ba204
    [<c007024c>] (bdi_register+0x0/0xac) from [<c0070324>] (bdi_register_dev+0x2c/0x34)
    r3:000000b3 r2:c02c0f24
    r5:c3987a00 r4:c39ba168
    [<c00702f8>] (bdi_register_dev+0x0/0x34) from [<c013a21c>] (add_disk+0x100/0x150)
    [<c013a11c>] (add_disk+0x0/0x150) from [<c01a4f54>] (mmc_blk_probe+0x224/0x2ec)
    r5:c3a9a120 r4:c388ddde
    [<c01a4d30>] (mmc_blk_probe+0x0/0x2ec) from [<c019f868>] (mmc_bus_probe+0x20/0x24)
    [<c019f848>] (mmc_bus_probe+0x0/0x24) from [<c0186eb0>] (driver_probe_device+0xa8/0x1bc)
    [<c0186e08>] (driver_probe_device+0x0/0x1bc) from [<c0187064>] (__device_attach+0x10/0x14)
    [<c0187054>] (__device_attach+0x0/0x14) from [<c0186448>] (bus_for_each_drv+0x68/0x94)
    [<c01863e0>] (bus_for_each_drv+0x0/0x94) from [<c01870f8>] (device_attach+0x64/0x7c)
    r7:c3987290 r6:c3a5ef60 r5:c39872b0 r4:c3987204
    [<c0187094>] (device_attach+0x0/0x7c) from [<c0186224>] (bus_attach_device+0x40/0x60)
    r5:c3987204 r4:c031c274
    [<c01861e4>] (bus_attach_device+0x0/0x60) from [<c0184ce0>] (device_add+0x4cc/0x688)
    r5:c3987204 r4:00000000
    [<c0184814>] (device_add+0x0/0x688) from [<c019fa00>] (mmc_add_card+0x88/0x134)
    [<c019f978>] (mmc_add_card+0x0/0x134) from [<c01a1548>] (mmc_attach_sd+0x15c/0x858)
    r5:00000000 r4:c3bfb960
    [<c01a13ec>] (mmc_attach_sd+0x0/0x858) from [<c019f610>] (mmc_rescan+0x228/0x29c)
    [<c019f3e8>] (mmc_rescan+0x0/0x29c) from [<c004842c>] (run_workqueue+0xe8/0x198)
    r6:c388c000 r5:c019f3e8 r4:c3885720
    [<c0048344>] (run_workqueue+0x0/0x198) from [<c0048ac8>] (worker_thread+0x5c/0xb8)
    r7:c03291d0 r6:c388dfa8 r5:c3885728 r4:c3885720
    [<c0048a6c>] (worker_thread+0x0/0xb8) from [<c004c428>] (kthread+0x58/0x8c)
    r6:c0048a6c r5:c3885720 r4:c388c000
    [<c004c3d0>] (kthread+0x0/0x8c) from [<c003abec>] (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.做事情,还是要有耐力和找到有效的办法,没有办法,也要尽可能地想办法。如果具备了一定的基础知识,加上细心观察,充分利用信息,很多时候,即使

  • 相关阅读:
    Spring Cloud 学习推荐
    Spring-Boot-应用可视化监控
    How to Convert a Class File to a Java File?
    Nacos Cluster Building
    基于Opentracing+Jaeger全链路灰度调用链
    Opentracing + Uber Jaeger 全链路灰度调用链,Nepxion Discovery
    What happened when new an object in JVM ?
    Sentinel Getting Started And Integration of Spring Cloud Alibaba Tutorials
    APK重签名总结
    C++矩阵运算库推荐
  • 原文地址:https://www.cnblogs.com/yuanfang/p/1914894.html
Copyright © 2011-2022 走看看