NAND驱动分析--(三)

本文深入分析了NAND Flash的MTD驱动程序实现原理,详细介绍了通过add_mtd_partitions创建分区的过程,并重点解读了mtdchar.c中的文件操作结构mtd_fops及其实现的mtd_open和mtd_read函数。

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

系统调用add_mtd_partitions(&priv->mtd, p1020_partition_info, 3)函数创建新分区的调用关系如下所示:

->add_mtd_partitions(&priv->mtd, p1020_partition_info, 3)
->add_mtd_device(&slave->mtd)
->mtd_table[i] = mtd;

由此可知,每个分区的mtd_info结构都添加到了mtd_table[i]数组当中。

现在分析\drivers\mtd\mtdchar.c代码,如下所示:

mtdchar.c是字符设备驱动程序的实现,它只需调用nand硬件驱动层的接口,即可实现对nand flash的操作。

1、file_operations

static struct file_operations mtd_fops = { //字符驱动程序的用户层接口实现
    .owner      = THIS_MODULE,
    .llseek     = mtd_lseek, //定位操作
    .read       = mtd_read, //读数据操作
    .write      = mtd_write, //写数据操作
    .ioctl      = mtd_ioctl, //特殊控制操作
    .open       = mtd_open, //打开设备
    .release    = mtd_close, //关闭设备
};

2、mtd_open

static int mtd_open(struct inode *inode, struct file *file)
{ //打开字符设备
    int minor = iminor(inode); //得到打开字符设备的从设备号
    int devnum = minor >> 1; //因为1个nand分区对应2个字符从设备,所以需要除以2来得到分区号
    struct mtd_info *mtd;

    DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n");

    if (devnum >= MAX_MTD_DEVICES)
        return -ENODEV;

    /* You can't open the RO devices RW */
    if ((file->f_mode & 2) && (minor & 1)) //当从设备号为奇数时,只能进行只读访问
        return -EACCES;

    /* 此函数将从mtd_table[i]数组中取得i=devnum时的mtd_info结构体 */
    mtd = get_mtd_device(NULL, devnum); //根据分区号来得到对应分区的mtd_info结构体

    if (!mtd)
        return -ENODEV;

    if (MTD_ABSENT == mtd->type) {
        put_mtd_device(mtd);
        return -ENODEV;
    }

    file->private_data = mtd; //将取得的mtd_info结构体赋给file的私有数据成员

    /* You can't open it RW if it's not a writeable device */
    if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
        put_mtd_device(mtd);
        return -EACCES;
    }

    return 0;
} /* mtd_open */

3、mtd_read

static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
{ //此函数用于实现字符设备读操作的用户层接口
    struct mtd_info *mtd = file->private_data; //首先取得对应分区的file私有数据中的mtd_info结构
    size_t retlen=0;
    size_t total_retlen=0;
    int ret=0;
    int len;
    char *kbuf; //定义一个字符指针,读出的数据首先存放于此

    DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");

    if (*ppos + count > mtd->size) //判断要读取的数据总数是否超出了分区的存储空间
        count = mtd->size - *ppos; //超出,修改要读取数据的总数

    if (!count)
        return 0;

    /* FIXME: Use kiovec in 2.5 to lock down the user's buffers
       and pass them directly to the MTD functions */
    while (count) {
        /* 判断所要读取的数据大小是否超出了所规定最大空间分配的大小(128K) */
        if (count > MAX_KMALLOC_SIZE) 
            len = MAX_KMALLOC_SIZE; //是,则分配最大空间
        else
            len = count; //否,则按count来分配

        kbuf=kmalloc(len,GFP_KERNEL); //分配内核空间,来存储读出的数据内容
        if (!kbuf)
            return -ENOMEM;

        /* 进行读数据操作,这是一个宏,其等价于mdt->read */
        ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); //len是准备读取数据的长度
        /* Nand returns -EBADMSG on ecc errors, but it returns
         * the data. For our userspace tools it is important
         * to dump areas with ecc errors ! 
         * Userspace software which accesses NAND this way
         * must be aware of the fact that it deals with NAND
         */
        if (!ret || (ret == -EBADMSG)) {
            *ppos += retlen;
            if (copy_to_user(buf, kbuf, retlen)) { //将内核空间的数据传递给用户空间,而此数据就是读出的nand数据
                    kfree(kbuf); //数据全部传出后,释放此内核空间
                return -EFAULT;
            }
            else
                total_retlen += retlen;

            count -= retlen; //当所要读取的数据总数超出最大分配内存空间时,while循环将继续
            buf += retlen;
        }
        else {
            kfree(kbuf);
            return ret;
        }

        kfree(kbuf);
    }

    return total_retlen;
} /* mtd_read */

其它的字符驱动程序用户层接口的实现就不再详细描述了,方法基本和上面mtd_read接口实现方法一致。

最后对字符设备进行注册后,就可以在用户空间通过应用程序来调用此nand flash的字符驱动了。代码如下:

static int __init init_mtdchar(void)
{
    /* 注册字符驱动程序,其主设备号为90 */
    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;
    }

    mtdchar_devfs_init();
    return 0;
}

至此nand flash驱动程序基本分析完毕,关于mtdblock.c的块设备驱动程序将不再进行分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值