1. Linux 2.6.20 SD/MMC卡驱动架构解析在嵌入式Linux系统中SD/MMC卡驱动是存储子系统的关键组成部分。以S3C2440平台为例Linux 2.6.20内核中的驱动架构主要分为四个层次总线管理层位于mmc_sysfs.c负责注册mmc_bus_type总线类型块设备层mmc_block.c实现块设备注册和队列管理核心协议层mmc.c处理基础通信协议硬件适配层s3cmci.c完成具体硬件操作驱动初始化时首先调用mmc_init()创建单线程工作队列kmmcd注册mmc_bus_type总线和mmc_host_class类。关键数据结构mmc_bus_type定义了总线名称、设备属性及各种回调函数static struct bus_type mmc_bus_type { .name mmc, .dev_attrs mmc_dev_attrs, .match mmc_bus_match, .uevent mmc_bus_uevent, .probe mmc_bus_probe, .remove mmc_bus_remove, .suspend mmc_bus_suspend, .resume mmc_bus_resume };注意总线匹配函数mmc_bus_match仅检查mmc_card的状态标志不涉及复杂匹配逻辑。这种设计使得驱动可以灵活处理不同状态的存储卡。2. 块设备驱动实现细节mmc_blk_init()函数完成块设备注册的核心工作通过register_blkdev()分配主设备号初始化mmc_driver结构体调用driver_register()将驱动注册到mmc总线关键数据结构mmc_driver包含了驱动名称和各类回调static struct mmc_driver mmc_driver { .drv { .name mmcblk, }, .probe mmc_blk_probe, .remove mmc_blk_remove, .suspend mmc_blk_suspend, .resume mmc_blk_resume };块设备探测函数mmc_blk_probe()会创建mmc_blk_data结构该结构封装了gendisk和mmc_queuestruct mmc_blk_data { struct mmc_queue queue; struct gendisk *disk; unsigned int usage; unsigned int read_only; unsigned int part_curr; int block_bits; };实际测试中发现块大小固定为512字节block_bits9这是SD/MMC规范的要求。驱动通过set_capacity()设置磁盘容量时需要将CSD寄存器中的容量值转换为512字节单位set_capacity(md-disk, card-csd.capacity (card-csd.read_blkbits - 9));3. S3C2440硬件适配层实现s3cmci.c文件实现了针对S3C2440芯片的硬件操作初始化流程s3cmci_init()注册平台驱动s3cmci_probe()分配mmc_host结构体mmc_alloc_host()创建host实例mmc_add_host()激活host关键操作host mmc_alloc_host(sizeof(struct s3cmci_host), pdev-dev); host-ops s3cmci_ops; host-f_min 400000; // 400kHz host-f_max 24000000; // 24MHz中断处理 卡检测中断触发mmc_detect_change()延时500ms后执行mmc_rescan()工作队列。这种延时设计有效避免了插拔时的机械抖动。实测中发现S3C2440的SDI控制器时钟需要特殊配置s3c2410-sdi s3c2410-sdi: running at 198kHz (requested: 197kHz)这是由PLL分频比限制导致的固有偏差在驱动中属于正常现象。4. 卡检测与初始化流程mmc_rescan()是卡初始化的核心函数主要步骤包括调用mmc_power_up()上电发送CMD0使卡进入IDLE状态通过CMD8检查SD卡版本2.0/1.1发送ACMD41CMD55初始化SD卡对于MMC卡则使用CMD1初始化成功初始化后读取CSD、CID等寄存器static void mmc_rescan(struct work_struct *work) { struct mmc_host *host container_of(work, struct mmc_host, detect.work); mmc_claim_host(host); if (host-ios.power_mode MMC_POWER_ON) mmc_check_cards(host); mmc_setup(host); mmc_release_host(host); }经验在S3C2440平台上ACMD41需要重试多次才能成功驱动中默认重试5次。遇到初始化失败时可适当增加重试次数。5. 请求处理流程分析IO请求处理采用标准的块设备队列机制文件系统通过submit_bio()提交请求块层合并请求后调用mmc_blk_issue_rq()构造mmc_request结构并提交到host控制器通过s3cmci_request()处理具体硬件操作请求处理的关键参数设置brq.cmd.arg req-sector 9; // 转换为字节地址 brq.data.blksz 1 md-block_bits; // 通常为512 brq.data.blocks req-nr_sectors (md-block_bits - 9);对于DMA传输驱动使用scatterlist管理分散内存brq.data.sg mq-sg; brq.data.sg_len blk_rq_map_sg(req-q, req, brq.data.sg);6. 常见问题排查指南CMD超时问题s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #2 op:APP_CMD(55)检查硬件连接和电压确保卡供电正常。必要时调整SDI时钟分频。卡检测不稳定 修改插卡检测去抖时间mmc_detect_change(host-mmc, msecs_to_jiffies(1000)); // 改为1秒大容量卡支持 对于4GB的SDHC卡需要处理EXT_CSD寄存器if (card-ext_csd.sectors) set_capacity(md-disk, card-ext_csd.sectors);性能优化 启用高速模式需要检查卡支持情况if (card-scr.sda_v3 host-caps MMC_CAP_SD_HIGHSPEED) mmc_switch(card, SD_SWITCH_CHECK, 0, 1, status);7. 关键调试技巧调试信息输出 在Makefile中添加CFLAGS_s3cmci.o : -DDEBUGsysfs节点检查cat /sys/bus/mmc/devices/mmc0\:*/cid性能分析 使用blktrace工具跟踪IO请求blktrace -d /dev/mmcblk0 -o traceDMA调试 检查DMA内存对齐if ((unsigned long)buf 0x3) { printk(KERN_WARNING Unaligned DMA buffer!\n); }通过深入理解Linux SD/MMC驱动架构开发者可以更好地移植和优化特定平台的存储驱动。在实际项目中建议重点关注硬件初始化时序、中断处理和DMA传输等关键环节。
Linux 2.6.20 SD/MMC卡驱动架构与实现解析
1. Linux 2.6.20 SD/MMC卡驱动架构解析在嵌入式Linux系统中SD/MMC卡驱动是存储子系统的关键组成部分。以S3C2440平台为例Linux 2.6.20内核中的驱动架构主要分为四个层次总线管理层位于mmc_sysfs.c负责注册mmc_bus_type总线类型块设备层mmc_block.c实现块设备注册和队列管理核心协议层mmc.c处理基础通信协议硬件适配层s3cmci.c完成具体硬件操作驱动初始化时首先调用mmc_init()创建单线程工作队列kmmcd注册mmc_bus_type总线和mmc_host_class类。关键数据结构mmc_bus_type定义了总线名称、设备属性及各种回调函数static struct bus_type mmc_bus_type { .name mmc, .dev_attrs mmc_dev_attrs, .match mmc_bus_match, .uevent mmc_bus_uevent, .probe mmc_bus_probe, .remove mmc_bus_remove, .suspend mmc_bus_suspend, .resume mmc_bus_resume };注意总线匹配函数mmc_bus_match仅检查mmc_card的状态标志不涉及复杂匹配逻辑。这种设计使得驱动可以灵活处理不同状态的存储卡。2. 块设备驱动实现细节mmc_blk_init()函数完成块设备注册的核心工作通过register_blkdev()分配主设备号初始化mmc_driver结构体调用driver_register()将驱动注册到mmc总线关键数据结构mmc_driver包含了驱动名称和各类回调static struct mmc_driver mmc_driver { .drv { .name mmcblk, }, .probe mmc_blk_probe, .remove mmc_blk_remove, .suspend mmc_blk_suspend, .resume mmc_blk_resume };块设备探测函数mmc_blk_probe()会创建mmc_blk_data结构该结构封装了gendisk和mmc_queuestruct mmc_blk_data { struct mmc_queue queue; struct gendisk *disk; unsigned int usage; unsigned int read_only; unsigned int part_curr; int block_bits; };实际测试中发现块大小固定为512字节block_bits9这是SD/MMC规范的要求。驱动通过set_capacity()设置磁盘容量时需要将CSD寄存器中的容量值转换为512字节单位set_capacity(md-disk, card-csd.capacity (card-csd.read_blkbits - 9));3. S3C2440硬件适配层实现s3cmci.c文件实现了针对S3C2440芯片的硬件操作初始化流程s3cmci_init()注册平台驱动s3cmci_probe()分配mmc_host结构体mmc_alloc_host()创建host实例mmc_add_host()激活host关键操作host mmc_alloc_host(sizeof(struct s3cmci_host), pdev-dev); host-ops s3cmci_ops; host-f_min 400000; // 400kHz host-f_max 24000000; // 24MHz中断处理 卡检测中断触发mmc_detect_change()延时500ms后执行mmc_rescan()工作队列。这种延时设计有效避免了插拔时的机械抖动。实测中发现S3C2440的SDI控制器时钟需要特殊配置s3c2410-sdi s3c2410-sdi: running at 198kHz (requested: 197kHz)这是由PLL分频比限制导致的固有偏差在驱动中属于正常现象。4. 卡检测与初始化流程mmc_rescan()是卡初始化的核心函数主要步骤包括调用mmc_power_up()上电发送CMD0使卡进入IDLE状态通过CMD8检查SD卡版本2.0/1.1发送ACMD41CMD55初始化SD卡对于MMC卡则使用CMD1初始化成功初始化后读取CSD、CID等寄存器static void mmc_rescan(struct work_struct *work) { struct mmc_host *host container_of(work, struct mmc_host, detect.work); mmc_claim_host(host); if (host-ios.power_mode MMC_POWER_ON) mmc_check_cards(host); mmc_setup(host); mmc_release_host(host); }经验在S3C2440平台上ACMD41需要重试多次才能成功驱动中默认重试5次。遇到初始化失败时可适当增加重试次数。5. 请求处理流程分析IO请求处理采用标准的块设备队列机制文件系统通过submit_bio()提交请求块层合并请求后调用mmc_blk_issue_rq()构造mmc_request结构并提交到host控制器通过s3cmci_request()处理具体硬件操作请求处理的关键参数设置brq.cmd.arg req-sector 9; // 转换为字节地址 brq.data.blksz 1 md-block_bits; // 通常为512 brq.data.blocks req-nr_sectors (md-block_bits - 9);对于DMA传输驱动使用scatterlist管理分散内存brq.data.sg mq-sg; brq.data.sg_len blk_rq_map_sg(req-q, req, brq.data.sg);6. 常见问题排查指南CMD超时问题s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #2 op:APP_CMD(55)检查硬件连接和电压确保卡供电正常。必要时调整SDI时钟分频。卡检测不稳定 修改插卡检测去抖时间mmc_detect_change(host-mmc, msecs_to_jiffies(1000)); // 改为1秒大容量卡支持 对于4GB的SDHC卡需要处理EXT_CSD寄存器if (card-ext_csd.sectors) set_capacity(md-disk, card-ext_csd.sectors);性能优化 启用高速模式需要检查卡支持情况if (card-scr.sda_v3 host-caps MMC_CAP_SD_HIGHSPEED) mmc_switch(card, SD_SWITCH_CHECK, 0, 1, status);7. 关键调试技巧调试信息输出 在Makefile中添加CFLAGS_s3cmci.o : -DDEBUGsysfs节点检查cat /sys/bus/mmc/devices/mmc0\:*/cid性能分析 使用blktrace工具跟踪IO请求blktrace -d /dev/mmcblk0 -o traceDMA调试 检查DMA内存对齐if ((unsigned long)buf 0x3) { printk(KERN_WARNING Unaligned DMA buffer!\n); }通过深入理解Linux SD/MMC驱动架构开发者可以更好地移植和优化特定平台的存储驱动。在实际项目中建议重点关注硬件初始化时序、中断处理和DMA传输等关键环节。