当前位置: 首页 > news >正文

linux2.6.28 MTD 内存技术设备(块设备)platform driver源码分析

//////////////////////drivers/mtd/nand/s3c_nand.c

module_init(s3c_nand_init);//模块初始化
static int __init s3c_nand_init(void)
{
printk(“S3C NAND Driver, © 2008 Samsung Electronics\n”);
platform_driver_register(&s3c6400_nand_driver);
platform_driver_register(&s3c6410_nand_driver);
}

////////////drivers/mtd/nand/s3c_nand.c
platform平台总线驱动结构体
static struct platform_driver s3c6410_nand_driver = {
.probe = s3c6410_nand_probe,
.remove = s3c_nand_remove,
.suspend = s3c_nand_suspend,
.resume = s3c_nand_resume,
.driver = {
.name = “s3c6410-nand”,
.owner = THIS_MODULE,
},
};

////////////drivers/mtd/nand/s3c_nand.c
static int s3c6410_nand_probe(struct platform_devicedev)
{
return s3c_nand_probe(dev, TYPE_S3C6410);
}
///////////////////////////////////////////////////drivers/mtd/nand/s3c_nand.c
/
s3c_nand_probe
*

  • called by device layer when it finds a device matching
  • one our driver can handled. This code checks to see if
  • it can allocate all necessary resources then calls the
  • nand layer to look for devices
    */
    //设备 和 驱动匹配到 后执行
    static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)
    {
    //在Mach-smdk6410.c (linux2.6.28\arch\arm\mach-s3c6410)文件中,有个函数:smdk6410_machine_init
    //s3c_device_nand.dev.platform_data = &s3c_nand_mtd_part_info; nand有关
    struct s3c_nand_mtd_info *plat_info = pdev->dev.platform_data;
    struct mtd_partition *partition_info = (struct mtd_partition *)plat_info->partition;
    struct nand_chip *nand;
    struct resource *res;
    int err = 0;
    int ret = 0;
    int i, j, size;

#if defined(CONFIG_MTD_NAND_S3C_HWECC)
struct nand_flash_dev *type = NULL;
u_char tmp;
#endif

/* get the clock source and enable it */ s3c_nand.clk = clk_get(&pdev->dev, "nand"); if (IS_ERR(s3c_nand.clk)) { dev_err(&pdev->dev, "failed to get clock"); err = -ENOENT; goto exit_error; } clk_enable(s3c_nand.clk); /* allocate and map the resource */

//得到I/O内存资源
/* currently we assume we have the one resource */
res = pdev->resource;
size = res->end - res->start + 1;
//I/O内存资源申请
s3c_nand.area = request_mem_region(res->start, size, pdev->name);

if (s3c_nand.area == NULL) { dev_err(&pdev->dev, "cannot reserve register region\n"); err = -ENOENT; goto exit_error; } s3c_nand.cpu_type = cpu_type; s3c_nand.device = &pdev->dev;

//将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问。
s3c_nand.regs = ioremap(res->start, size);

if (s3c_nand.regs == NULL) { dev_err(&pdev->dev, "cannot reserve register region\n"); err = -EIO; goto exit_error; } /* allocate memory for MTD device structure and private data */ s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!s3c_mtd) { printk("Unable to allocate NAND MTD dev structure.\n"); return -ENOMEM; } /* Get pointer to private data */

//kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); 跳过sizeof(struct mtd_info)个字节

nand = (struct nand_chip *) (&s3c_mtd[1]);

/* Initialize structures */ memset((char *) s3c_mtd, 0, sizeof(struct mtd_info)); memset((char *) nand, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ s3c_mtd->priv = nand; for (i = 0; i < plat_info->chip_nr; i++) {

//上面s3c_nand.regs = ioremap(res->start, size); 所以是nand的基地址
////#define S3C_NFDATA S3C2410_NFREG(0x10)

图片

nand->IO_ADDR_R = (char *)(s3c_nand.regs + S3C_NFDATA); nand->IO_ADDR_W = (char *)(s3c_nand.regs + S3C_NFDATA); nand->cmd_ctrl = s3c_nand_hwcontrol; nand->dev_ready = s3c_nand_device_ready; nand->scan_bbt = s3c_nand_scan_bbt; nand->options = 0;

#if defined(CONFIG_MTD_NAND_S3C_CACHEDPROG)
nand->options |= NAND_CACHEPRG;
#endif

#if defined(CONFIG_MTD_NAND_S3C_HWECC)
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.hwctl = s3c_nand_enable_hwecc;
nand->ecc.calculate = s3c_nand_calculate_ecc;
nand->ecc.correct = s3c_nand_correct_data;

s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE); s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE); s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); s3c_nand_device_ready(0); tmp = readb(nand->IO_ADDR_R); /* Maf. ID */ 制造商ID tmp = readb(nand->IO_ADDR_R); /* Device ID */设备ID for (j = 0; nand_flash_ids[j].name != NULL; j++) { if (tmp == nand_flash_ids[j].id) { type = &nand_flash_ids[j]; break; } } if (!type) { printk("Unknown NAND Device.\n"); goto exit_error; } nand->cellinfo = readb(nand->IO_ADDR_R); /* the 3rd byte */ tmp = readb(nand->IO_ADDR_R); /* the 4th byte */ if (!type->pagesize) { if (((nand->cellinfo >> 2) & 0x3) == 0) { nand_type = S3C_NAND_TYPE_SLC; nand->ecc.size = 512; nand->ecc.bytes = 4; if ((1024 << (tmp & 0x3)) > 512) { nand->ecc.read_page = s3c_nand_read_page_1bit; nand->ecc.write_page = s3c_nand_write_page_1bit; nand->ecc.read_oob = s3c_nand_read_oob_1bit; nand->ecc.write_oob = s3c_nand_write_oob_1bit; nand->ecc.layout = &s3c_nand_oob_64; } else { nand->ecc.layout = &s3c_nand_oob_16; } } else { nand_type = S3C_NAND_TYPE_MLC; nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */ nand->ecc.read_page = s3c_nand_read_page_4bit; nand->ecc.write_page = s3c_nand_write_page_4bit; nand->ecc.size = 512; nand->ecc.bytes = 8; /* really 7 bytes */ nand->ecc.layout = &s3c_nand_oob_mlc_64; } } else { nand_type = S3C_NAND_TYPE_SLC; nand->ecc.size = 512; nand->cellinfo = 0; nand->ecc.bytes = 4; nand->ecc.layout = &s3c_nand_oob_16; } printk("S3C NAND Driver is using hardware ECC.\n");

#else
nand->ecc.mode = NAND_ECC_SOFT;//软件ECC
printk(“S3C NAND Driver is using software ECC.\n”);
#endif
if (nand_scan(s3c_mtd, 1)) {//以mtd_info为参数调用nand_scan()函数探测NAND Flash的存在
ret = -ENXIO;
goto exit_error;
}

/* Register the partitions */

//如果要分区,则以mtd_info和mtd_partition为参 数调用add_mtd_partitions(),添加分区信息
add_mtd_partitions(s3c_mtd, partition_info, plat_info->mtd_part_nr);
}

pr_debug("initialized ok\n"); return 0;

exit_error:
kfree(s3c_mtd);

return ret;

}

/////////////////////////////drivers/mtd/nand/s3c_nand.c
struct s3c_nand_info {
/* mtd info */
struct nand_hw_control controller;
struct s3c_nand_mtd_info *mtds;
struct s3c2410_platform_nand *platform;

/* device info */ struct device *device; struct resource *area; struct clk *clk; void __iomem *regs; void __iomem *sel_reg; int sel_bit; int mtd_count; enum s3c_cpu_type cpu_type;

};
static struct s3c_nand_info s3c_nand;

http://www.jsqmd.com/news/506936/

相关文章:

  • Python-100-Days装饰器与生成器:提升代码优雅度的工具
  • 数据集处理革命:Yi-Coder-1.5B智能数据清洗方案
  • GitHub_Trending/ms/MS-DOS引导扇区代码分析:系统启动的第一扇区
  • 勃农免耕机制造企业价格多少,性价比咋样? - 工业推荐榜
  • 基于STM32的智能衣柜环境自适应调节系统开发
  • MQTT Retain / Last Will / Clean Session 深度解析:智能设备在线状态设计
  • YLB3118@ACP# 芯片产品规格解析及应用场景总结
  • Dioxus组件样式方案对比:CSS-in-Rust vs CSS Modules
  • 好用的勃农免耕机品牌,吉林地区有靠谱厂家推荐吗? - myqiye
  • Cloudflare测速文件终极指南:如何用官方链接精准测试你的网络带宽(附100MB-1GB链接)
  • 当我的“龙虾”OpenClaw 决定通宵修仙:24 小时生成 700 万字《凡人修仙传》实录
  • 【Linux:文件 + 进程】进程间通信进阶(2)
  • 2026东莞房屋装修攻略:鲁班装饰全案整装解决8大核心痛点 - 速递信息
  • MogFace-large模型效果可视化:使用Matplotlib绘制PR曲线与混淆矩阵
  • 2026年3月轻集料混凝土批发厂家热门推荐,速来了解,专业的轻集料混凝土深度剖析助力明智之选 - 品牌推荐师
  • ViGEmBus虚拟游戏控制器驱动:终极安装与使用完整指南
  • 磁力密封与高精度控制双核心:206高温高压釜技术优势及市场洞察 - 品牌推荐大师
  • WarcraftHelper完整指南:终极解决魔兽争霸3现代系统兼容性问题
  • 小米新模型让社区对 DeepSeek V4 耿耿于怀:但真正的变量,可能根本不在 benchmark 上
  • 逆向实战:Buuctf网鼎杯jocker题目中的堆栈修复与动态调试技巧
  • 2026年苏州雨水收集设备来样定制厂家推荐,费用怎么算 - mypinpai
  • Zig日志聚合:集中管理应用日志的终极指南
  • QML系统时间日期处理详解
  • 一站式Windows部署神器:MediaCreationTool.bat高效解决全版本系统安装难题
  • 2026年教育招聘公司分析:有实战演练培训的公司怎么选择? - 工业品牌热点
  • ASTM D4169标准,ASTM D4169最常用的选择,如何进行ASTMD4169测试
  • 电容充电仿真实战:用LTspice XVII验证RC电路的时间常数理论
  • 解决OSX-KVM黑屏问题:EFI日志分析与排错流程
  • Z-Image-Turbo-辉夜巫女网络配置详解:保障模型API在复杂计算机网络中的稳定访问
  • Ostrakon-VL-8B惊艳效果:同一模型完成文字识别、合规打分、改进建议生成