本文只是对该函数的注释,方便之后查阅,可能有误,请高手指正。
/**
* nand_fill_oob - [INTERN] Transfer client buffer to oob
* @mtd: MTD device structure
* @oob: oob data buffer
* @len: oob data write length
* @ops: oob ops structure
*/
static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd_to_nand(mtd);
/*
* Initialise to all 0xFF, to avoid the possibility of left over OOB
* data from a previous OOB read.
*/
memset(chip->oob_poi, 0xff, mtd->oobsize);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_RAW:
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
return oob + len;
case MTD_OPS_AUTO_OOB: {
struct nand_oobfree *free = chip->ecc.layout->oobfree;
uint32_t boffs = 0, woffs = ops->ooboffs;
size_t bytes = 0;
for (; free->length && len; free++, len -= bytes) {
/* Write request not from offset 0? */
if (unlikely(woffs)) {
if (woffs >= free->length) {
woffs -= free->length;
continue;
}
boffs = free->offset + woffs;
bytes = min_t(size_t, len,
(free->length - woffs));
woffs = 0;
} else {
bytes = min_t(size_t, len, free->length);
boffs = free->offset;
}
memcpy(chip->oob_poi + boffs, oob, bytes);
oob += bytes;
}
return oob;
}
default:
BUG();
}
return NULL;
}
这个函数不长。
1. 首先看一下三个宏的注释
/**
* MTD operation modes
*
* @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default)这个说是会把oob放置在指定的位置
* @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas
* which are defined by the internal ecclayout这个说是把oob放置到空闲的位置,空闲位置由ecclayout指定
* @MTD_OPS_RAW: data are transferred as-is, with no error correction;
* this mode implies %MTD_OPS_PLACE_OOB
* 这个说,数据和它本身一致,没有ecc
* These modes can be passed to ioctl(MEMWRITE) and are also used internally.
* See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs.
* %MTD_FILE_MODE_RAW.
*/
enum {
MTD_OPS_PLACE_OOB = 0,
MTD_OPS_AUTO_OOB = 1,
MTD_OPS_RAW = 2,
};
2. memset(chip->oob_poi, 0xff, mtd->oobsize);
对oob的数组填充0xff。mtd->oobsize指定缓存有多大。
3.case MTD_OPS_PLACE_OOB:
case MTD_OPS_RAW:
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
return oob + len;
对于以上两种情况,ops->ooboffs 指定偏移地址,oob指向存有ecc的缓存,len指定oob缓存中有的字节数。
就是,拷贝oob中的数据到chip->oob_poi这个数组中(注意下标被指定了ops->ooboffs,而可能是不为0的),拷贝的字节数为len
其中oob的值由参数传入,len的值由参数传入。
注意返回值为oob + len,是个地址值。
4. 对于自动放置的情况
case MTD_OPS_AUTO_OOB: {
struct nand_oobfree *free = chip->ecc.layout->oobfree; //oobfree 是指的空闲区的头指针,可能不止一个
uint32_t boffs = 0, woffs = ops->ooboffs; //起始位置
size_t bytes = 0;
//需要考虑的情况是一个空闲区域可能写不下,所以要for循环处理。
for (; free->length && len; free++, len -= bytes) { //空闲区长度不为0,且要写的长度len不为0
/* Write request not from offset 0? */
if (unlikely(woffs)) { //woffs 大于 0。 //woffs取0的可能性比较大
if (woffs >= free->length) { 大于等于,写的偏移比空闲长度大。因为指定了偏移woffs,所以要把前面的位置空出来。
woffs -= free->length; //减去
continue;
}
boffs = free->offset + woffs; //开始写的位置boffs,此时woffs可能还不为0,但是已经小于free->length,所以还要在偏移一点点woffs,但是这次已经落在free区间了。
bytes = min_t(size_t, len,
(free->length - woffs)); //取出较小的值
woffs = 0; //偏移清零
} else { //woffs 等于0
bytes = min_t(size_t, len, free->length); //对len和free->length取个小的
boffs = free->offset; //起始位置,是free区域的起始偏移位置
}
memcpy(chip->oob_poi + boffs, oob, bytes); //写入字节,最大长度为bytes
oob += bytes; //oob的指针向后移动。
} //end for
return oob;
} //end case
分析到此结束。
应该来说还是比较简单。