MTD源码分析(2)

mtdchar.c

MTD
字符设备的文件

notifier

MTD 字符设备的 notifier

static struct mtd_notifier notifier = {          

       add: mtd_notify_add,

       remove:   mtd_notify_remove,

};

 

mtd_lseek

格式:

       static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)

注释:

      

功能:

       MTD 字符设备的指针

说明:

      

参数:

       file MTD 字符设备文件

       offset :偏移

       orig :设置方式

返回:

       成功:返回当前指针位置

       设置方式无效:返回 -EINVAL

调用:

      

被调用:

       注册进 mtd_fops 结构

源代码:

{

       struct mtd_info *mtd=(struct mtd_info *)file->private_data;

 

       switch (orig) {

       case 0:

              /* SEEK_SET */

              file->f_pos = offset;

              break;

       case 1:

              /* SEEK_CUR */

              file->f_pos += offset;

              break;

       case 2:

              /* SEEK_END */

              file->f_pos =mtd->size + offset;

              break;

       default:

              return -EINVAL;

       }

 

       if (file->f_pos < 0)

              file->f_pos = 0;

       else if (file->f_pos >= mtd->size)

              file->f_pos = mtd->size - 1;

 

       return file->f_pos;

}

 

 

mtd_open

格式:

       static int mtd_open(struct inode *inode, struct file *file)

注释:

      

功能:

       打开一个 MTD 字符设备

说明:

       devnum=minor>>2 (参看 Documentations/devices.txt ),

       进行安全性检查,

       调用 get_mtd_device 获取 MTD 设备,并将 file->private_data 指向它

参数:

       inode FIXME

       file :是系统提供给 MTD 字符设备用于传递参数的 file 结构,此函数中它的 private_data

成员被指向原始设备层的 MTD 设备

返回:

       成功:返回 0

       失败:返回错误码

调用:

       get_mtd_device() 获得原始设备层的 MTD 设备

被调用:

       注册进 mtd_fops 结构

源代码:

{

       int minor = MINOR(inode->i_rdev);

       int devnum = minor >> 1;

       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 = get_mtd_device(NULL, devnum);

      

       if (!mtd)

              return -ENODEV;

      

       if (MTD_ABSENT == mtd->type) {

              put_mtd_device(mtd);

              return -ENODEV;

       }

 

       file->private_data = mtd;

             

       /* 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 */

 

 

 

 

mtd_close

格式:

       static int mtd_close(struct inode *inode, struct file *file)

注释:

      

功能:

       关闭一个 MTD 字符设备

说明:

       调用 mtd_info->sync() 同步 MTD 设备,

       调用 put_mtd_device() 返还 MTD 设备

参数:

       inode FIXME

       file :无用

返回:

       返回 0

调用:

       mtd_info->sync() 同步 MTD 设备

put_mtd_device() 返还 MTD 设备

被调用:

       被注册进 mtd_fops 结构

源代码:

{

       struct mtd_info *mtd;

 

       DEBUG(MTD_DEBUG_LEVEL0, "MTD_close/n");

 

       mtd = (struct mtd_info *)file->private_data;

      

       if (mtd->sync)

              mtd->sync(mtd);

      

       put_mtd_device(mtd);

 

       return 0;

} /* mtd_close */

 

MAX_KMALLOC_SIZE

/* FIXME: This _really_ needs to die. In 2.5, we should lock the

   userspace buffer down and use it directly with readv/writev.

*/

#define MAX_KMALLOC_SIZE 0x20000

 

 

mtd_read

格式:

       static ssize_t mtd_read(struct file *file, char *buf, size_t count,loff_t *ppos)

注释:

      

功能:

       MTD 字符设备的写操作

说明:

       count>0 {

              裁减本次操作大小 len min(MAX_KMALLOC_SIZE,count)

              申请一块大小为 MAX_KMALLOC_SIZE 的内核空间 kbuf

              调用 mtd_info->read MTD 设备中的数据读入 kbuf

              kbuf 中的数据拷贝到用户空间 buf

              count 自减

              释放 kbuf

       }

参数:

file :系统给 MTD 字符设备驱动程序用于传递参数的 file 结构,此函数通过 file 得到下

层的 MTD 设备

       buf :用户空间的指针,用于存放读取的数据

       count :被读数据的长度

       ppos :被读数据在 MTD 设备中的位置

返回:

       成功:返回实际读取数据的长度

       失败:返回错误码

调用:

       mtd_info->read() 用于从 MTD 设备中读取数据

被调用:

       被注册进 mtd_fops 结构

源代码:

{

       struct mtd_info *mtd = (struct mtd_info *)file->private_data;

       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) {

              if (count > MAX_KMALLOC_SIZE)

                     len = MAX_KMALLOC_SIZE;

              else

                     len = count;

 

              kbuf=kmalloc(len,GFP_KERNEL);

              if (!kbuf)

                     return -ENOMEM;

             

              ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);

              if (!ret) {

                     *ppos += retlen;

                     if (copy_to_user(buf, kbuf, retlen)) {

                             kfree(kbuf);

                            return -EFAULT;

                     }

                     else

                            total_retlen += retlen;

 

                     count -= retlen;

                     buf += retlen;

              }

              else {

                     kfree(kbuf);

                     return ret;

              }

             

              kfree(kbuf);

       }

      

       return total_retlen;

} /* mtd_read */

 

 

 

mtd_write

格式:

       static ssize_t mtd_write(struct file *file, const char *buf, size_t count,loff_t *ppos)

注释:

      

功能:

       MTD 字符设备的写操作

说明:

       count>0 {

              裁减本次操作大小 len min(MAX_KMALLOC_SIZE,count)

              申请一块大小为 MAX_KMALLOC_SIZE 的内核空间 kbuf

              将用户空间 buf 中的数据拷贝到 kbuf

              调用 mtd_info->write kbuf 中的数据读入 MTD 设备,

              count 自减

              释放 kbuf

       }

参数:

file :系统给 MTD 字符设备驱动程序用于传递参数的 file 结构,此函数通过 file 得到下

层的 MTD 设备

       buf :用户空间的指针,用于存放将要写入的数据

       count :被写数据的长度

       ppos :数据被写入 MTD 设备中的位置

返回:

       成功:返回实际读取数据的长度

       失败:返回错误码

调用:

       mtd_info->write 用于写入 MTD 设备

被调用:

       被注册进 mtd_fops 结构

源代码:

{

       struct mtd_info *mtd = (struct mtd_info *)file->private_data;

       char *kbuf;

       size_t retlen;

       size_t total_retlen=0;

       int ret=0;

       int len;

 

       DEBUG(MTD_DEBUG_LEVEL0,"MTD_write/n");

      

       if (*ppos == mtd->size)

              return -ENOSPC;

      

       if (*ppos + count > mtd->size)

              count = mtd->size - *ppos;

 

       if (!count)

              return 0;

 

       while (count) {

              if (count > MAX_KMALLOC_SIZE)

                     len = MAX_KMALLOC_SIZE;

              else

                     len = count;

 

              kbuf=kmalloc(len,GFP_KERNEL);

              if (!kbuf) {

                     printk("kmalloc is null/n");

                     return -ENOMEM;

              }

 

              if (copy_from_user(kbuf, buf, len)) {

                     kfree(kbuf);

                     return -EFAULT;

              }

             

               ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);

              if (!ret) {

                     *ppos += retlen;

                     total_retlen += retlen;

                     count -= retlen;

                     buf += retlen;

              }

              else {

                     kfree(kbuf);

                     return ret;

              }

             

              kfree(kbuf);

       }

 

       return total_retlen;

} /* mtd_write */

 

 

mtd_erase_callback

格式:

       static void mtd_erase_callback (struct erase_info *instr)

注释:

      

功能:

       唤醒进程

说明:

       在擦除进行完后被调用

参数:

       instr :进行的擦除的 erase_info 结构

返回:

      

调用:

       wake_up()

被调用:

       mtd_ioctl 中被赋给 erase_info->callback

源代码:

{

       wake_up((wait_queue_head_t *)instr->priv);

}

 

 

mtd_ioctl

格式:

       static int mtd_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)

注释:

      

功能:

       MTD 字符设备的 IO 控制

说明:

       根据 cmd 分别处理

参数:

       inode FIXME

       file :传递参数的结构

       cmd IO 控制的命令

       arg IO 控制的参数

返回:

       成功:返回 0

       失败:返回错误码

调用:

      

被调用:

       注册进 mtd_fops 结构

源代码:

{

       struct mtd_info *mtd = (struct mtd_info *)file->private_data;

       int ret = 0;

       u_long size;

      

       DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl/n");

 

       size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;

       if (cmd & IOC_IN) {

              ret = verify_area(VERIFY_READ, (char *)arg, size);

              if (ret) return ret;

       }

       if (cmd & IOC_OUT) {

              ret = verify_area(VERIFY_WRITE, (char *)arg, size);

              if (ret) return ret;

       }

      

       switch (cmd) {

       case MEMGETREGIONCOUNT:

              if (copy_to_user((int *) arg, &(mtd->numeraseregions), sizeof(int)))

                     return -EFAULT;

              break;

 

       case MEMGETREGIONINFO:

       {

              struct region_info_user ur;

 

              if (copy_from_user(      &ur,

                                   (struct region_info_user *)arg,

                                   sizeof(struct region_info_user))) {

                     return -EFAULT;

              }

 

              if (ur.regionindex >= mtd->numeraseregions)

                     return -EINVAL;

              if (copy_to_user((struct mtd_erase_region_info *) arg,

                            &(mtd->eraseregions[ur.regionindex]),

                            sizeof(struct mtd_erase_region_info)))

                     return -EFAULT;

              break;

       }

 

       case MEMGETINFO:

              if (copy_to_user((struct mtd_info *)arg, mtd,

                              sizeof(struct mtd_info_user)))

                     return -EFAULT;

              break;

 

       case MEMERASE:

       {

              struct erase_info *erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);

              if (!erase)

                     ret = -ENOMEM;

              else {

                     wait_queue_head_t waitq;

                     DECLARE_WAITQUEUE(wait, current);

 

                     init_waitqueue_head(&waitq);

 

                     memset (erase,0,sizeof(struct erase_info));

                     if (copy_from_user(&erase->addr, (u_long *)arg,

                                      2 * sizeof(u_long))) {

                            kfree(erase);

                            return -EFAULT;

                     }

                     erase->mtd = mtd;

                     erase->callback = mtd_erase_callback;

                     erase->priv = (unsigned long)&waitq;

                    

                     /*

                       FIXME: Allow INTERRUPTIBLE. Which means

                       not having the wait_queue head on the stack.

                      

                       If the wq_head is on the stack, and we

                       leave because we got interrupted, then the

                       wq_head is no longer there when the

                       callback routine tries to wake us up.

                     */

                     ret = mtd->erase(mtd, erase);

                     if (!ret) {

                            set_current_state(TASK_UNINTERRUPTIBLE);

                            add_wait_queue(&waitq, &wait);

                            if (erase->state != MTD_ERASE_DONE &&

                                 erase->state != MTD_ERASE_FAILED)

                                   schedule();

                            remove_wait_queue(&waitq, &wait);

                            set_current_state(TASK_RUNNING);

 

                            ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0;

                     }

                     kfree(erase);

              }

              break;

       }

 

       case MEMWRITEOOB:

       {

              struct mtd_oob_buf buf;

              void *databuf;

              ssize_t retlen;

             

              if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))

                     return -EFAULT;

             

              if (buf.length > 0x4096)

                     return -EINVAL;

 

              if (!mtd->write_oob)

                     ret = -EOPNOTSUPP;

              else

                     ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);

 

              if (ret)

                     return ret;

 

              databuf = kmalloc(buf.length, GFP_KERNEL);

              if (!databuf)

                     return -ENOMEM;

             

              if (copy_from_user(databuf, buf.ptr, buf.length)) {

                     kfree(databuf);

                     return -EFAULT;

              }

 

              ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);

 

              if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))

                     ret = -EFAULT;

 

              kfree(databuf);

              break;

 

       }

 

       case MEMREADOOB:

       {

              struct mtd_oob_buf buf;

              void *databuf;

              ssize_t retlen;

 

              if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))

                     return -EFAULT;

             

              if (buf.length > 0x4096)

                     return -EINVAL;

 

              if (!mtd->read_oob)

                     ret = -EOPNOTSUPP;

              else

                     ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);

 

              if (ret)

                     return ret;

 

              databuf = kmalloc(buf.length, GFP_KERNEL);

              if (!databuf)

                     return -ENOMEM;

             

              ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);

 

              if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))

                     ret = -EFAULT;

              else if (retlen && copy_to_user(buf.ptr, databuf, retlen))

                     ret = -EFAULT;

             

              kfree(databuf);

              break;

       }

 

       case MEMLOCK:

       {

              unsigned long adrs[2];

 

              if (copy_from_user(adrs ,(void *)arg, 2* sizeof(unsigned long)))

                     return -EFAULT;

 

              if (!mtd->lock)

                     ret = -EOPNOTSUPP;

              else

                     ret = mtd->lock(mtd, adrs[0], adrs[1]);

              break;

       }

 

       case MEMUNLOCK:

       {

              unsigned long adrs[2];

 

              if (copy_from_user(adrs, (void *)arg, 2* sizeof(unsigned long)))

                     return -EFAULT;

 

              if (!mtd->unlock)

                     ret = -EOPNOTSUPP;

              else

                     ret = mtd->unlock(mtd, adrs[0], adrs[1]);

              break;

       }

 

             

       default:

              DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)/n", cmd, MEMGETINFO);

              ret = -ENOTTY;

       }

 

       return ret;

} /* memory_ioctl */

 

 

 

mtd_fops

MTD 字符设备的操作函数结构

static struct file_operations mtd_fops = {                  

       owner:           THIS_MODULE,

       llseek:             mtd_lseek,         /* lseek */

       read:              mtd_read,       /* read */

       write:            mtd_write,     /* write */

       ioctl:              mtd_ioctl,       /* ioctl */

       open:              mtd_open,      /* open */

       release:    mtd_close,      /* release */

};

 

 

 

init_mtdchar

格式:

       static int __init init_mtdchar(void)

注释:

      

功能:

       初始化一个 MTD 字符设备(设备层)

说明:

       如果定义了 CONFIG_DEVFS_FS{

调用 devfs_register_chrdev() 注册 MTD 字符设备

调用 register_mtd_user() 将设备层 MTD 字符设备的 notifier 注册进原始设备层

       }

       否则调用 register_chrdev() 注册 MTD 字符设备

参数:

      

返回:

       成功:返回 0

       注册失败:返回 -EAGAIN

调用:

       devfs_register_chrdev() register_chrdev() 注册字符设备

被调用:

       __init

       module_init

源代码:

{

#ifdef CONFIG_DEVFS_FS

       if (devfs_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;

       }

 

       devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL);

 

       register_mtd_user(&notifier);

#else

       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;

       }

#endif

 

       return 0;

}

 

cleanup_mtdchar

格式:

       static void __exit cleanup_mtdchar(void)

注释:

      

功能:

       清除 MTD 字符设备

说明:

       如果定义了 CONFIG_DEVFS_FS{

              调用 unregister_mtd_user() 注销 MTD 字符设备的 notifier,

              调用 devfs_unregister_chrdev() 注销 MTD 字符设备

}

否则调用 unregister_chrdev() 注销 MTD 字符设备

参数:

      

返回:

      

调用:

       unregister_chrdev() devfs_unregister_chrdev() 注销字符设备

被调用:

       __exit

       module_exit

源代码:

{

#ifdef CONFIG_DEVFS_FS

       unregister_mtd_user(&notifier);

       devfs_unregister(devfs_dir_handle);

       devfs_unregister_chrdev(MTD_CHAR_MAJOR, "mtd");

#else

       unregister_chrdev(MTD_CHAR_MAJOR, "mtd");

#endif

}

/drivers/mtd/chips 子目录

/drivers/mtd/chips 下文件的主要功能是探测 MTD ,该目录下文件是 chipreg.c gen_probe.c cfi_probe.c jedec_probe.c cfi_cmdset_0001.c cfi_cmdset_0002.c map_rom.c map_ram.c map_absent.c amd_flash.c jedec.c sharp.c ,下面介绍每个文件的功能

为了确定一个 Flash 是否是一个 CFI 使能的 flash memory 器件,首先要往 Flash 的地址 0x55H 写入数据 0x98H ,然后从 Flash 的地址 0x10H 处开始连续读取 3 个存储单元中的内容,如果数据总线返回的 3 个存储单元的字符分别为 'Q','R' 'Y' ,那么该器件是一个 CFI 使能的 Flash 。在识别 Flash CFI 使能器件后,通过查询命令来读取 CFI 查询结构,这些数据的地址和含义在 cfi_ident.h 文件中。探测 CFI 接口 Flash 设备的程序在文件 cfi_probe.c 中,这些设备的类型为“ cfi_probe ”。

也可以用 JEDEC (电子电器设备联合会)标准设备模仿 CFI 接口,探测 JEDEC 设备的程序在 jedec_probe.c 中, JEDEC 设备的类型为“ jedec_probe ”。

CFI 设备和 JEDEC 设备都要用到 gen_probe.c 文件。

不同的制造商使用不同的命令集,目前 Linux MTD 实现的命令集有 AMD/Fujitsu 的标准命令集和 Intel/Sharp 的扩展命令集(兼容 Intel/Sharp 标准命令集)两个,这两个命令集分别在 cfi_cmdset_0002.c cfi_cmdset_0001.c 中实现。

此外还有一些非 CFI 标准的 Flash ,其中“ jedec ”类型的 Flash 的探测程序在 jedec.c , sharp ”类型的 Flash 的探测程序在 sharp.c 中“ amd_flash ”类型的 Flash 的探测程序在 amd_flash.c 中。

       最后,还有一些非 Flash MTD ,比如 ROM absent (无)设备。这些设备的探测程序在 map_rom.c map_ram.c map_absent.c 中。

       所有类型的芯片都通过 chipreg.c 中的 do_map_probe() 程序驱动

 

chipreg.c

关于 MTD 芯片注册的文件,此文件中定义的 chip_drvs_list 是所有芯片类型的驱动器链表,在 /drivers/mtd/chips 子目录下的其他文件通过调用 register_mtd_chip_driver() unregister_mtd_chip_driver() 向此链表中添加或去除 MTD 芯片驱动器。

/drivers/mtd/map/ 下的文件根据芯片类型调用 do_map_probe() do_map_probe() 通过 get_mtd_chip_driver() 获得符合指定 name MTD 芯片驱动器,再调用获得的芯片驱动器的 probe 程序。

chip_drvs_list

static LIST_HEAD(chip_drvs_list);

MTD 芯片驱动器列表

 

register_mtd_chip_driver

格式:

       void register_mtd_chip_driver(struct mtd_chip_driver *drv)

注释:

      

功能:

       注册 MTD 的芯片驱动器

说明:

       chip_drvs_list 里添加 mtd_chip_driver

参数:

       drv :被注册的 MTD 的芯片驱动器

返回:

      

调用:

       list_add()

被调用:

各种芯片驱动的初始化程序

源代码:

{

       spin_lock(&chip_drvs_lock);

       list_add(&drv->list, &chip_drvs_list);

       spin_unlock(&chip_drvs_lock);

}

 

 

unregister_mtd_chip_driver

格式:

       void unregister_mtd_chip_driver(struct mtd_chip_driver *drv)

注释:

      

功能:

       删除一个 MTD 芯片的驱动器

说明:

       chip_drvs_list 中删除一个 mtd_chip_driver

参数:

       drv :被删除的 MTD 芯片的驱动器

返回:

      

调用:

       list_del()

被调用:

       各种芯片驱动的清除程序

源代码:

{

       spin_lock(&chip_drvs_lock);

       list_del(&drv->list);

       spin_unlock(&chip_drvs_lock);

}

 

 

get_mtd_chip_driver

格式:

       static struct mtd_chip_driver *get_mtd_chip_driver (char *name)

注释:

      

功能:

获得指定名称的 MTD 的芯片驱动器

说明:

       根据 name chip_drvs_list 中获得一个 mtd_chip_driver

参数:

       name :该芯片驱动器的名称

返回:

       找到:返回该 mtd_chip_driver

       没找到:返回 NULL

调用:

      

被调用:

       do_map_probe

源代码:

{

       struct list_head *pos;

       struct mtd_chip_driver *ret = NULL, *this;

 

       spin_lock(&chip_drvs_lock);

 

       list_for_each(pos, &chip_drvs_list) {

              this = list_entry(pos, typeof(*this), list);

             

              if (!strcmp(this->name, name)) {

                     ret = this;

                     break;

              }

       }

       if (ret && !try_inc_mod_count(ret->module)) {

              /* Eep. Failed. */

              ret = NULL;

       }

 

       spin_unlock(&chip_drvs_lock);

 

       return ret;

}

 

do_map_probe

格式:

struct mtd_info *do_map_probe(char *name, struct map_info *map)

注释:

      

功能:

       根据 name map 的信息探测 MTD 并返回 mtd_info 结构

说明:

1.  根据 name 获得 mtd_chip_driver

2.  调用 mtd_chip_driver 中的 probe 函数

参数:

       name MTD 芯片类型

       map MTD 芯片信息

返回:

       成功:返回 MTD 设备的结构 mtd_info

       失败:返回 NULL

调用:

       get_mtd_chip_driver()

       drv->probe()

被调用:

       /drivers/mtd/maps/ 下的板子相关文件中的 init_xxxx

源代码:

{

       struct mtd_chip_driver *drv;

       struct mtd_info *ret;

 

       drv = get_mtd_chip_driver(name);

 

       if (!drv && !request_module(name))

              drv = get_mtd_chip_driver(name);

 

       if (!drv)

              return NULL;

 

       ret = drv->probe(map);

#ifdef CONFIG_MODULES

       /* We decrease the use count here. It may have been a

          probe-only module, which is no longer required from this

          point, having given us a handle on (and increased the use

          count of) the actual driver code.

       */

       if(drv->module)

              __MOD_DEC_USE_COUNT(drv->module);

#endif

 

       if (ret)

              return ret;

      

       return NULL;

}

 

cfi_probe.c

“cfi_probe” 型芯片的探测程序,主要由 cfi_chip_probe() cfi_probe() cfi_chip_setup() qry_present() cfi_probe_init() cfi_probe_exit() 这几个函数组成。

cfi_probe() “cfi_probe” 类型芯片的探测程序,它调用通用探测程序 mtd_do_chip_probe() ,并将 cfi_chip_probe 作为参数传递给 mtd_do_chip_probe() mtd_do_chip_probe() 将间接调用 cfi_chip_probe 的成员函数 cfi_probe_chip() cfi_probe() 注册在 “cfi_probe” 芯片的驱动器 cfi_chipdrv 中。

cfi_probe_chip() 将调用 qry_present() cfi_chip_setup() 初始化 cfi_private 结构, qry_presetn() 负责验证该 MTD 设备支持 CFI 接口, cfi_chip_setup() 则读出 CFI 查询结构中的数据(见 cfi.h

cfi_probe_init() cfi_probe_exit() “cfi_prbe” 型芯片驱动器的注册程序和清除程序。

 

 

cfi_chipdrv

static struct mtd_chip_driver cfi_chipdrv = {

       probe: cfi_probe,           芯片的探测程序

       name: "cfi_probe",         芯片名称

       module: THIS_MODULE

};

“cfi_probe” 类型 MTD 芯片的驱动器

 

cfi_probe_init

格式:

       int __init cfi_probe_init(void)

注释:

      

功能:

       初始化 “cfi_probe” 类型的 MTD 芯片

说明:

       调用 register_mtd_chip_driver() cfi_chipdrv 加入 MTD 驱动器列表 chip_drvs_list

参数:

      

返回:

       0

调用:

       register_mtd_chip_driver()

被调用:

       __init

       module_init

源代码:

{

       register_mtd_chip_driver(&cfi_chipdrv);

       return 0;

}

 

cfi_probe_exit

格式:

static void __exit cfi_probe_exit(void)

注释:

      

功能:

       清除 “cfi_probe”MTD 芯片驱动

说明:

       调用 unregister_mtd_chip_driver MTD 芯片驱动器列表 chip_drvs_list 中删除 cfi_chipdrv

参数:

      

返回:

      

调用:

       unregister_mtd_chip_driver()

被调用:

       __exit

       module_exit

源代码:

{

       unregister_mtd_chip_driver(&cfi_chipdrv);

}

 

cfi_probe

格式:

struct mtd_info *cfi_probe(struct map_info *map)

注释:

      

功能:

       “cfi_probe” 类型 MTD 芯片的探测程序

说明:

       调用通用的探测程序 mtd_do_chip_probe() ,并将 cfi_chip_probe 作为参数传进去

参数:

       map :芯片的相关信息

返回:

       MTD 设备信息结构 mtd_info

调用:

       mtd_do_chip_probe

被调用:

       注册在 cfi_chipdrv 中,根据芯片类型被 do_map_probe() 调用

源代码:

{

       /*

         * Just use the generic probe stuff to call our CFI-specific

         * chip_probe routine in all the possible permutations, etc.

         */

       return mtd_do_chip_probe(map, &cfi_chip_probe);

}

 

 

cfi_chip_probe

static struct chip_probe cfi_chip_probe = {

       name: "CFI",

       probe_chip: cfi_probe_chip

};

cfi_probe 传递给通用探测程序 mtd_do_chip_probe 的参数

 

 

cfi_probe_chip

格式:

static int cfi_probe_chip(struct map_info *map, __u32 base,

                       struct flchip *chips, struct cfi_private *cfi)

注释:

      

功能:

       “cfi_probe” 类型 MTD 芯片驱动程序

说明:

1.  调用 qry_present() 检查是否 CFI 接口的 MTD

2.  如果 cfi->numchips=0 ,调用 cfi_chip_setup() 设置;(搜索新芯片)

3.  否则探测此芯片是否为原芯片的别名,如果不是,此芯片作为同类芯片加入

参数:

       FIXME

返回:

       成功:返回 1

       失败:返回 0 -1

调用:

       qry_present()

       cfi_chip_setup()

被调用:

       注册在 cfi_chip_probe

源代码:

{

       int i;

      

       cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);   //reset ,进入读模式

       cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);       // 发送查询命令

 

       if (!qry_present(map,base,cfi))            // 如果不存在 QRY ,则不是 CFI 接口

              return 0;

 

       if (!cfi->numchips) {             // 如果是 MTD 原始设备中的第一块芯片

              /* This is the first time we're called. Set up the CFI

                 stuff accordingly and return */

              return cfi_chip_setup(map, cfi);

       }

 

       /* Check each previous chip to see if it's an alias */

       for (i=0; i<cfi->numchips; i++) {

              /* This chip should be in read mode if it's one

                 we've already touched. */

              if (qry_present(map,chips[i].start,cfi)) {

                     /* Eep. This chip also had the QRY marker.

                       * Is it an alias for the new one? */

                     cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);

 

                     /* If the QRY marker goes away, it's an alias */

                     if (!qry_present(map, chips[i].start, cfi)) {

                            printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx/n",

                                   map->name, base, chips[i].start);

                            return 0;

                     }

                     /* Yes, it's actually got QRY for data. Most

                       * unfortunate. Stick the new chip in read mode

                       * too and if it's the same, assume it's an alias. */

                     /* FIXME: Use other modes to do a proper check */

                     cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

                    

                     if (qry_present(map, base, cfi)) {

                            printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx/n",

                                   map->name, base, chips[i].start);

                            return 0;

                     }

              }

       }

      

       /* OK, if we got to here, then none of the previous chips appear to

          be aliases for the current one. */

       if (cfi->numchips == MAX_CFI_CHIPS) {

              printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d./n", map->name, MAX_CFI_CHIPS);

              /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */

              return -1;

       }

       chips[cfi->numchips].start = base;

       chips[cfi->numchips].state = FL_READY;

       cfi->numchips++;

      

       /* Put it back into Read Mode */

       cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

 

       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode/n",

              map->name, cfi->interleave, cfi->device_type*8, base,

              map->buswidth*8);

      

       return 1;

}

 

 

qry_present

格式:

       static inline int qry_present(struct map_info *map, __u32 base,

                            struct cfi_private *cfi)

注释:

/* check for QRY, or search for jedec id.

   in: interleave,type,mode

   ret: table index, <0 for error

  */   

功能:

       检查 QRY

说明:

       读出从 0x10 开始的三个字节,如果为 ”QRY” ,则说明是 CFI 接口的 MTD

参数:

       map :芯片信息

       base :基地址

       cfi CFI 私有信息

返回:

       成功:返回 1

       失败:返回 0

调用:

      

被调用:

       cfi_probe_chip()

源代码:

{

       int osf = cfi->interleave * cfi->device_type; // scale factor

 

       if (cfi_read(map,base+osf*0x10)==cfi_build_cmd('Q',map,cfi) &&

           cfi_read(map,base+osf*0x11)==cfi_build_cmd('R',map,cfi) &&

           cfi_read(map,base+osf*0x12)==cfi_build_cmd('Y',map,cfi))

              return 1;  // ok !

 

       return 0;        // nothing found

}

 

cfi_chip_setup

格式:

       static int cfi_chip_setup(struct map_info *map,

                 struct cfi_private *cfi)

注释:

      

功能:

       设置 cfi_private 结构变量 cfi 的成员 cfiq cfi_ident 结构)

说明:

1.  读取器件可擦除块区域个数

2.  分配并清零内存块

3.  调用 cfi_read_query() 读取 CFI 数据结构 cfi_ident

参数:

       map :芯片信息

       cfi :被设置的 cfi_private 结构

返回:

       成功:返回 1

       失败:返回 0

调用:

      

被调用:

       cfi_chip_probe()

源代码:

{

       int ofs_factor = cfi->interleave*cfi->device_type;

       __u32 base = 0;

       int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);

       int i;

 

#ifdef DEBUG_CFI

       printk("Number of erase regions: %d/n", num_erase_regions);

#endif

       if (!num_erase_regions)

              return 0;

 

       cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);

       if (!cfi->cfiq) {

              printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure/n", map->name);

              return 0;

       }

      

       memset(cfi->cfiq,0,sizeof(struct cfi_ident));      

      

       cfi->cfi_mode = 1;        //JEDEC 仿真模式

       cfi->fast_prog=1;          /* CFI supports fast programming */ //CFI 支持 Fast Program 模式

      

       /* Read the CFI info structure */

       for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {

              ((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);

       }

      

       /* Do any necessary byteswapping */

       cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);

      

       cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR);

       cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID);

       cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR);

       cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc);

       cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize);

 

#ifdef DEBUG_CFI

       /* Dump the information therein */

       print_cfi_ident(cfi->cfiq);

#endif

 

       for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {

              cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]);

             

#ifdef DEBUG_CFI             

              printk("  Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks/n",

                     i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff,

                     (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);

#endif

       }

       /* Put it back into Read Mode */

       cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

 

       return 1;

}

 

 

jedec_probe.c

“jedec_probe” 型芯片的探测程序,主要由 jedec_probe() jedec_probe_chip() cfi_jedec_setup() jedec_probe_init() jedec_probe_exit() 这几个函数组成。

jedec_probe() “jedec_probe” 类型芯片的探测程序,它调用通用探测程序 mtd_do_chip_probe() ,并将 jedec_chip_probe 作为参数传递给 mtd_do_chip_probe() mtd_do_chip_probe() 将间接调用 jedec_chip_probe 的成员函数 jedec_probe_chip() jedec_probe() 注册在 “jedec_probe” 芯片的驱动器 jedec_chipdrv 中。

jedec_probe_chip() 调用 cfi_jedec_setup() 初始化 cfi_private 结构, cfi_jedec_setup() 根据

jedec_probe_init() jedec_probe_exit() “cfi_prbe” 型芯片驱动器的注册程序和清除程序

 

 

amd_flash_info

struct amd_flash_info {

       const __u16 mfr_id;

       const __u16 dev_id;

       const char *name;

       const int DevSize;

       const int InterfaceDesc;

       const int NumEraseRegions;

       const int CmdSet;

       const ulong regions[4];

};

AMD Flash 芯片的信息结构

 

 

jedec_table

static const struct amd_flash_info jedec_table[] = {}

包含各种 jedec_probe 类型芯片信息的结构

 

 

jedec_chipdrv

static struct mtd_chip_driver jedec_chipdrv = {

       probe: jedec_probe,              芯片的探测程序

       name: "jedec_probe",     芯片名称

       module: THIS_MODULE

};

“jedec_probe” 型芯片的驱动器

 

jedec_probe_init

格式:

       int __init jedec_probe_init(void)

注释:

      

功能:

       初始化 “jedec_probe” 类型的 MTD 芯片

说明:

       调用 register_mtd_chip_driver() jedec_chipdrv 加入 MTD 驱动器列表 chip_drvs_list

参数:

      

返回:

       0

调用:

       register_mtd_chip_driver()

被调用:

       __init

       module_init

源代码:

{

       register_mtd_chip_driver(&jedec_chipdrv);

       return 0;

}

 

 

jedec_probe_exit

格式:

       static void __exit jedec_probe_exit(void)

注释:

      

功能:

       清除 “jedec_probe”MTD 芯片驱动

说明:

       调用 unregister_mtd_chip_driver MTD 芯片驱动器列表 chip_drvs_list 中删除 jedec_chipdrv

参数:

      

返回:

      

调用:

       unregister_chip_driver

被调用:

       __exit

       module_exit

源代码:

{

       unregister_mtd_chip_driver(&jedec_chipdrv);

}

 

 

jedec_probe

格式:

       struct mtd_info *jedec_probe(struct map_info *map)

注释:

      

功能:

       “jedec_probe” MTD 芯片的探测程序

说明:

       调用通用探测程序 mtd_do_chip_probe() ,并将 jedec_chip_probe 作为参数传递给 mtd_do_chp_probe()

参数:

       map :芯片信息

返回:

       MTD 设备信息结构 mtd_info

调用:

       mtd_do_chip_probe()

被调用:

       注册在 jedec_chipdrv 中,根据芯片类型被 do_map_probe() 调用

源代码:

{

       /*

         * Just use the generic probe stuff to call our CFI-specific

         * chip_probe routine in all the possible permutations, etc.

         */

       return mtd_do_chip_probe(map, &jedec_chip_probe);

}

 

jedec_probe_chip

static struct chip_probe jedec_chip_probe = {

       name: "JEDEC",

       probe_chip: jedec_probe_chip

};

jedec_probe 传递给通用探测程序 mtd_do_chip_probe 的参数

 

 

jedec_probe_chip

格式:

       static int jedec_probe_chip(struct map_info *map, __u32 base,

                            struct flchip *chips, struct cfi_private *cfi)

注释:

      

功能:

       “jedec_probe” 类型 MTD 芯片驱动程序

说明:   

       主要工作是设置传进的 cfi_private 型参数 cfi

参数:

       FIXME

返回:

       成功:返回 1

       失败:返回 0

调用:

       cfi_jedec_stup()

被调用:

       注册在 jedec_chip_probe

源代码:

      

 

 

cfi_jedec_setup

格式:

static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)

注释:

      

功能:

       根据 index jedec_table 中选择对应的信息赋给 p_cfi

说明:

      

参数:

       p_cfi cfi_private 结构的 CFI 私有信息

       index :芯片在 jedec_table 中的索引

返回:

       成功:返回 1

       失败:返回 0

调用:

      

被调用:

       jedec_probe_chip()

源代码:

      

 

 

 

gen_probe.c

通用芯片探测程序,由 mtd_do_chip_probe() genprobe_ident_chips() genprobe_new_chip() check_cmd_set() cfi_cmdset_unknown() 组成

cfi_probe() jedec_probe() 调用 mtd_do_chip_probe() mtd_do_chip_probe() 调用 genprobe_ident_chips() genprobe_ident_chips() 调用 genprobe_new_chip() genprobe_new_chip() 则调用 mtd_do_chip_probe() 的参数 chip_probe->probe_chip()

 

mtd_do_chip_probe

格式:

       struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)

注释:

      

功能:

       根据 MTD 芯片的信息 map 和参数 cp 返回 MTD 设备 mtd_info 结构

说明:

       获得 cfi_private 结构

       调用 check_cmd_set() 返回 mtd_info 结构

参数:

       map MTD 芯片信息

       cp :由 cfi_probe() jedec_probe() 传进来的信息

返回:

       MTD 设备信息

调用:

       genprobe_ident_chips()

       check_cmd_set()

被调用:      

       cfi_probe()

       jedec_probe()

源代码:

{

       struct mtd_info *mtd = NULL;

       struct cfi_private *cfi;

 

       /* First probe the map to see if we have CFI stuff there. */

       cfi = genprobe_ident_chips(map, cp);

      

       if (!cfi)

              return NULL;

 

       map->fldrv_priv = cfi;

       /* OK we liked it. Now find a driver for the command set it talks */

 

       mtd = check_cmd_set(map, 1); /* First the primary cmdset */

       if (!mtd)

              mtd = check_cmd_set(map, 0); /* Then the secondary */

      

       if (mtd)

              return mtd;

 

       printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found/n");

      

       kfree(cfi->cfiq);

       kfree(cfi);

       map->fldrv_priv = NULL;

       return NULL;

}

 

 

 

genprobe_ident_chips

格式:

       struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)

注释:

      

功能:

       生成 cfi_private 结构并返回

说明:

1.  调用 genprobe_new_chip 搜索第一块 flash 芯片

2.  设置 cfi.chipshift ,并将 cfi.numchips 设置为 1

3.  循环调用 cp->probe_chip() 搜索所有的 flash 芯片

参数:

       map :芯片信息

       cp chip_probe 结构参数

返回:

       cfi_private 结构

调用:

       genprobe_new_chip()

被调用:

       mtd_do_chip_probe()

源代码:

      

 

genprobe_new_chip

格式:

       static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,

                          struct cfi_private *cfi)

注释:

      

功能:

       设置 cfi

说明:

       调用 cp->probe_chip()

参数:

       map :芯片信息

       cp chip_probe 结构参数

       cfi :被设置的 cfi_private 结构

返回:

       成功:返回 1

       失败:返回 0

调用:

       cfi-> probe_chip()

被调用:

       genprobe_ident_chips()

源代码:

      

 

 

 

check_cmd_set

格式:

       static struct mtd_info *check_cmd_set(struct map_info *map, int primary)

注释:

      

功能:

       根据 map_info 中的厂商信息调用不同的命令集

说明:

       根据厂商类型调用两个不同的命令集, cfi_cmdset_0001() cfi_cmdset_0002() ,如果符合的类型没有则调用 cfi_cmdset_unkown

参数:

       map MTD 芯片信息

       primary :如果取 1 ,则芯片厂商信息为 map 中的 primary ,否则为 auxillary

返回:

       MTD 设备信息 mtd_info

调用:

       cfi_cmdset_0001()

       cfi_cmdset_0002()

       cfi_cmdset_unknown()

被调用:

       mtd_do_chip_probe()

源代码:

{

       struct cfi_private *cfi = map->fldrv_priv;

       __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;

      

       if (type == P_ID_NONE || type == P_ID_RESERVED)

              return NULL;

 

       switch(type){

              /* Urgh. Ifdefs. The version with weak symbols was

                * _much_ nicer. Shame it didn't seem to work on

                * anything but x86, really.

                * But we can't rely in inter_module_get() because

                * that'd mean we depend on link order.

                */

#ifdef CONFIG_MTD_CFI_INTELEXT

       case 0x0001:

       case 0x0003:

              return cfi_cmdset_0001(map, primary);

#endif

#ifdef CONFIG_MTD_CFI_AMDSTD

       case 0x0002:

              return cfi_cmdset_0002(map, primary);

#endif

       }

 

       return cfi_cmdset_unknown(map, primary);

}

 

cfi_cmdset_unkown

格式:

       static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, int primary)

注释:

      

功能:

       调用未知类型的命令集

说明:

       如果存在返回 mtd_info ,如果不存在返回 NULL

参数:

       map MTD 芯片信息

       primary FIXME

返回:

       存在命令集:返回 mtd_info

       否则:返回 NULL

调用:

      

被调用:

       check_cmd_set()

源代码:

{

       struct cfi_private *cfi = map->fldrv_priv;

       __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;

#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE)

       char probename[32];

       cfi_cmdset_fn_t *probe_function;

 

       sprintf(probename, "cfi_cmdset_%4.4X", type);

             

       probe_function = inter_module_get_request(probename, probename);

 

       if (probe_function) {

              struct mtd_info *mtd;

 

              mtd = (*probe_function)(map, primary);

              /* If it was happy, it'll have increased its own use count */

              inter_module_put(probename);

              return mtd;

       }

#endif

       printk(KERN_NOTICE "Support for command set %04X not present/n",

              type);

 

       return NULL;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值