NAND驱动分析--(三)

来源:互联网 发布:t95e6最新版本数据 编辑:程序博客网 时间:2024/06/06 10:06

系统调用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的块设备驱动程序将不再进行分析。

原创粉丝点击