VIVI中MTD驱动的实现(1)
来源:互联网 发布:吉他指板淘宝 编辑:程序博客网 时间:2024/05/14 18:57
在vivi中使用的flash有nor和nand,而mtd的作用就是提供一个中间层的驱动,实现接口函数的统一管理,这里首先介绍nand flash在mtd中的实现。
在vivi bootloader中,第6步的时候就是实现mtd中间驱动的实现,MTD驱动的函数调用关系如下:
mtd_dev_init()---->mtd_init()---->smc_init()在这里需要说明,mtd_init()函数可以按照配置调用不同的函数,包括cfi_init(),smc_init(),amd_init(),这里不同的函数对应不同的flash设备的初始化。
其中cfi_init()是intel发起的nor flash的接口标准。
smc_init()是smc智能卡接口,我们使用的nand flash使用的就是这个接口
amd_init()是AMD flash接口
在完成上面初始化以后则是增加flash命令,这部分于后面的增加命令相似(关于命令的部分在后面的章节会有专门的说明)
---->add_command(&flash_command)
下面来具体看看函数的实现,首先我们要注意到的是两个数据结构,分别是mtd_info(mtd_info是表示MTD设备的结构,每个分区也被表示为一个mtd_info,如果有两个MTD设备,每个设备有三个分区,那么在系统中就一共有6个mtd_info结构),一下是vivi中mtd_info结构
struct mtd_info {
u_char type;
u_int32_t flags;
u_int32_t size; // Total size of the MTD
/* "Major" erase size for the device. Naïve users may take this
* to be the only erase size available, or may use the more detailed
* information below if they desire
*/
u_int32_t erasesize;
u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
u_int32_t ecctype;
u_int32_t eccsize;
// Kernel-only stuff starts here.
char *name;
int index;
/* Data for variable erase regions. If numeraseregions is zero,
* it means that the whole device has erasesize as given above.
*/
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
/* This really shouldn't be here. It can go away in 2.5 */
u_int32_t bank_size;
struct module *module;
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
void (*unpoint) (struct mtd_info *mtd, u_char * addr);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
/*
* Methods to access the protection register area, present in some
* flash devices. The user data is one time programmable but the
* factory data is read only.
*/
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
/* This function is not yet implemented */
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
/* Chip-supported device locking */
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
void *priv;
};
还有一个重要的结构nand_chip,这个结构中包含了nand flash所有的信息
/*
* NAND Private Flash Chip Data
*
* Structure overview:
*
* IO_ADDR_R - address to read the 8 I/O lines of the flash device
*
* IO_ADDR_W - address to write the 8 I/O lines of the flash device
*
* hwcontrol - hardwarespecific function for accesing control-lines
*
* dev_ready - hardwarespecific function for accesing device ready/busy line
*
* chip_lock - spinlock used to protect access to this structure
*
* wq - wait queue to sleep on if a NAND operation is in progress
*
* state - give the current state of the NAND device
*
* page_shift - number of address bits in a page (column address bits)
*
* data_buf - data buffer passed to/from MTD user modules
*
* data_cache - data cache for redundant page access and shadow for
* ECC failure
*
* ecc_code_buf - used only for holding calculated or read ECCs for
* a page read or written when ECC is in use
*
* reserved - padding to make structure fall on word boundary if
* when ECC is in use
*/
struct nand_chip {
#ifdef CONFIG_MTD_NANDY
void (*hwcontrol)(int cmd);
void (*write_cmd)(u_char val);
void (*write_addr)(u_char val);
u_char (*read_data)(void);
void (*write_data)(u_char val);
void (*wait_for_ready)(void);
/*spinlock_t chip_lock;*/
/*wait_queue_head_t wq;*/
/*nand_state_t state;*/
int page_shift;
u_char *data_buf;
u_char *data_cache;
int cache_page;
struct nand_smc_dev *dev;
u_char spare[SMC_OOB_SIZE];
#else /* CONFIG_MTD_NANDY */
unsigned long IO_ADDR_R;
unsigned long IO_ADDR_W;
void (*hwcontrol)(int cmd);
int (*dev_ready)(void);
int chip_delay;
/*spinlock_t chip_lock;*/
/*wait_queue_head_t wq;*/
/*nand_state_t state;*/
int page_shift;
u_char *data_buf;
u_char *data_cache;
int cache_page;
#ifdef CONFIG_MTD_NAND_ECC
u_char ecc_code_buf[6];
u_char reserved[2];
#endif
#endif /* CONFIG_MTD_NANDY */
};
/*
* NAND Flash Device ID Structure
*
* Structure overview:
*
* name - Complete name of device
*
* manufacture_id - manufacturer ID code of device.
*
* model_id - model ID code of device.
*
* chipshift - total number of address bits for the device which
* is used to calculate address offsets and the total
* number of bytes the device is capable of.
*
* page256 - denotes if flash device has 256 byte pages or not.
*
* pageadrlen - number of bytes minus one needed to hold the
* complete address into the flash array. Keep in
* mind that when a read or write is done to a
* specific address, the address is input serially
* 8 bits at a time. This structure member is used
* by the read/write routines as a loop index for
* shifting the address out 8 bits at a time.
*
* erasesize - size of an erase block in the flash device.
*/
struct nand_flash_dev {
char * name;
int manufacture_id;
int model_id;
int chipshift;
char page256;
char pageadrlen;
unsigned long erasesize;
};
首先看看上面三个结构,了解结构中包含的信息
在回来继续分析smc_init()函数,首先函数需要申请一个地址空间用来存放struct mtd_info和struct nand_chip,返回地址给mymtd
mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
定义一个nand_chip结构的变量this; struct nand_chip *this
this = (struct nand_chip *)(&mymtd[1])这个地方有必要解释一下:
其中,mymtd是指向struct mtd_info的指针,那么mymtd[1]实际上是等效于*(mymtd + 1)的数学计算模式,注意mymtd并非数组,这里仅仅利用了编译器翻译的特点。对于指针而言,加1实际上增加的指针对应类型的值,在这里地址实际上增加了sizeof(struct mtd_info),因为前面分配了两块连续的地址空间,所以&(*(mymtd + 1))实际上就是mtd_info数据结构结束的下一个地址,然后实现强制转换,于是this就成为了nand_chip的入口指针了。但是,这里必须要把握好,因为这个地方是不会进行内存的检查的,也就是说,如果你使用了mymtd[2],那么仍然按照上述公式解析,虽然可以运算,可是就是明显的指针泄漏了,可能会出现意料不到的结果。写了一个测试程序,对这点进行了探讨,要小心内存问题。(参考了CalmArrow的解释)
static int
smc_init(void)
{
struct nand_chip *this;
//u_int16_t nfconf;
u_int16_t nfcont;
/* Allocate memory for MTD device structure and private data */
mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
if (!mymtd) {
printk("Unable to allocate S3C2440 NAND MTD device structure./n");
return -ENOMEM;
}
/* Get pointer to private data */
this = (struct nand_chip *)(&mymtd[1]);
/* Initialize structures */
memset((char *)mymtd, 0, sizeof(struct mtd_info));
memset((char *)this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
mymtd->priv = this;
/* set NAND Flash controller */
nfcont = NFCONT;
/* NAND Flash controller enable */
nfcont |= NFCONT_FCTRL_EN;
nfcont |= NFCONT_ECC_INIT;
nfcont |= NFCONT_MAINECC_LOCK;
NFCONT = nfcont;
/* Set flash memory timing */
// nfconf &= ~NFCONF_TWRPH1;
// nfconf |= NFCONF_TWRPH1_7;
// nfconf &= ~NFCONF_TWRPH0;
// nfconf |= NFCONF_TWRPH0_7;
// nfconf &= ~NFCONF_TACLS;
// nfconf &= ~NFCONF_TACLS_7;
// NFCONF = nfconf;
/* Set address of NAND IO lines */
this->hwcontrol = smc_hwcontrol;
this->write_cmd = write_cmd;
this->write_addr = write_addr;
this->read_data = read_data;
this->write_data = write_data;
this->wait_for_ready = wait_for_ready;
/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */
//this->hwcontrol(NAND_CTL_SETNCE);
// this->write_cmd(NAND_CMD_RESET);
// this->wait_for_ready();
// this->hwcontrol(NAND_CTL_CLRNCE);
smc_insert(this);
return 0;
}
紧接着就是初始两个结构
memset((char *)mymtd, 0, sizeof(struct mtd_info));
memset((char *)this, 0, sizeof(struct nand_chip));
使得mymtd->priv指向this结构。也就是使得这两部分联系起来
设置nand flash的寄存器
NFCONT |= ((1<<0) & (1 << 4) & (1 << 5));
由于nand_chip是直接于nanf flash挂钩的,应此在此定义一些函数直接对nand flash进行操作
先看整体,再对每个细节进行分析:
this->hwcontrol = smc_hwcontrol;
this->write_cmd = write_cmd;
this->write_addr = write_addr;
this->read_data = read_data;
this->write_data = write_data;
this->wait_for_ready = wait_for_ready;
我们首先来看smc_hwcontrol函数,也就是nand flash的硬件控制,实现很简单,根据vivi中定义的情况之处理3中情况(1,2,10,其他的命令只是简单的退出)
static void smc_hwcontrol(int cmd)
{
swith (cmd)
{
case NAND_CTL_SETNCE:
NFCONT &= NFCONT_nFCE_HIGH;
break;
//enable chip select NFCONT &= ~(1 << 1)
case NAND_CTL_CLRNCE:
NFCONT |= NFCONT_nFCE_HIGH;
break;
//disable chip select NFCONT |= (1 << 1)
case NAND_CTL_CLRRnB:
NFSTAR |= NFSTAT_RnB;
break;
// RnB is detected! NFSTAT |= (1 << 2)
}
}
写命令:
static void write_cmd(u_char val)
{
NFCMD = (u_char)val;
}
static void write_addr(u_char val)
{
NFADDR = (u_char)val;
}
static u_char read_data(void)
{
return (u_char)NFDATA;
}
static void write_data(u_char val)
{
NFDATA = (u_char)val;
}
等待准备好:
static void wait_for_ready(void)
{
//NFSTAT bit[2]为0的时候则表示没准备好,当Bit[2]等于1的时候,则准备好
while (!(NFSTAT & (1 << 2)))
;//do nothing
}
- VIVI中MTD驱动的实现(1)
- uClinux下的MTD技术(1):Flash驱动实现
- vivi分析-NandFlash的操作(mtd&&bon)-1
- vivi中命令的实现
- v4l2视频驱动中关于vivi.c的个人分析(菜鸟入门,请轻拍!)
- Linux MTD驱动下的Nand Flash驱动中 mtd->write_oob和ecc.write_oob
- Linux2.6内核的vivi分区及内核MTD分区
- Linux2.6内核的vivi分区及内核MTD分区
- Linux2.6内核的vivi分区及内核MTD分区
- Linux2.6内核的vivi分区及内核MTD分区
- MTD驱动1
- 基于MTD的NANDFLASH设备驱动底层实现原理分析
- 基于MTD的NANDFLASH设备驱动底层实现原理分析 .
- vivi boot loader的实现
- vivi boot loader的实现
- 用vivi模拟向内核中加入自己的驱动模块
- 基于MTD的NAND驱动开发(1、2、3)
- 1、基于MTD的NAND驱动开发(一)
- 2704
- 利用java的ZipOutputStream类压缩文件,解压文件或文件夹中的文件
- 再谈个性化
- 几年时间, 很长...
- 以后每天要有2-3个小时关掉电脑
- VIVI中MTD驱动的实现(1)
- vc本地编码程序在日文系统出现乱码无法使用的解决办法
- 《C和指针》学习笔记(六)
- Linux Shell 下的输出重定向
- Android shell命令大全
- 晨星怎么了?Mstar回归半年前
- 关于java绝对路径和相对路径:
- [如何控制Log 1]分别在Linux和Android中用C语言写系统日志
- [如何控制Log 2]android的logcat详细用法