📄 doc2000.c
字号:
up(&this->lock); return -EIO; } DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0, CDSN_CTRL_ECC_IO); } DoC_WriteBuf(this, &buf[len256], len - len256); if (eccbuf) { WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl); if (DoC_is_Millennium(this)) { WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); } else { WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg); } WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, CDSNControl); /* Read the ECC data through the DiskOnChip ECC logic */ for (di = 0; di < 6; di++) { eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); } /* Reset the ECC engine */ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);#ifdef PSYCHO_DEBUG printk ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4], eccbuf[5]);#endif } DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); /* There's an implicit DoC_WaitReady() in DoC_Command */ if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error programming flash\n"); /* Error in programming */ *retlen = 0; up(&this->lock); return -EIO; } /* Let the caller know we completed it */ *retlen += len; if (eccbuf) { unsigned char x[8]; size_t dummy; int ret; /* Write the ECC data to flash */ for (di=0; di<6; di++) x[di] = eccbuf[di]; x[6]=0x55; x[7]=0x55; ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); if (ret) { up(&this->lock); return ret; } } to += len; left -= len; buf += len; } up(&this->lock); return 0;}static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel){ static char static_buf[512]; static DECLARE_MUTEX(writev_buf_sem); size_t totretlen = 0; size_t thisvecofs = 0; int ret= 0; down(&writev_buf_sem); while(count) { size_t thislen, thisretlen; unsigned char *buf; buf = vecs->iov_base + thisvecofs; thislen = vecs->iov_len - thisvecofs; if (thislen >= 512) { thislen = thislen & ~(512-1); thisvecofs += thislen; } else { /* Not enough to fill a page. Copy into buf */ memcpy(static_buf, buf, thislen); buf = &static_buf[thislen]; while(count && thislen < 512) { vecs++; count--; thisvecofs = min((512-thislen), vecs->iov_len); memcpy(buf, vecs->iov_base, thisvecofs); thislen += thisvecofs; buf += thisvecofs; } buf = static_buf; } if (count && thisvecofs == vecs->iov_len) { thisvecofs = 0; vecs++; count--; } ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel); totretlen += thisretlen; if (ret || thisretlen != thislen) break; to += thislen; } up(&writev_buf_sem); *retlen = totretlen; return ret;}static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t * retlen, u_char * buf){ struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; int len256 = 0, ret; unsigned long docptr; struct Nand *mychip; down(&this->lock); docptr = this->virtadr; mychip = &this->chips[ofs >> this->chipshift]; if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with doc_read_ecc. */ if (this->page256) { if (!(ofs & 0x8)) ofs += 0x100; else ofs -= 0x8; } DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0); /* treat crossing 8-byte OOB data for 2M x 8bit devices */ /* Note: datasheet says it should automaticaly wrap to the */ /* next OOB block, but it didn't work here. mf. */ if (this->page256 && ofs + len > (ofs | 0x7) + 1) { len256 = (ofs | 0x7) + 1 - ofs; DoC_ReadBuf(this, buf, len256); DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), CDSN_CTRL_WP, 0); } DoC_ReadBuf(this, &buf[len256], len - len256); *retlen = len; /* Reading the full OOB data drops us off of the end of the page, * causing the flash device to go into busy mode, so we need * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ ret = DoC_WaitReady(this); up(&this->lock); return ret;}static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, size_t * retlen, const u_char * buf){ struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; int len256 = 0; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; volatile int dummy; int status; // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len, // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]); /* Find the chip which is to be used and select it */ if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; /* disable the ECC engine */ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_DIS, docptr, ECCConf); /* Reset the chip, see Software Requirement 11.4 item 1. */ DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP); /* issue the Read2 command to set the pointer to the Spare Data Area. */ DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with doc_read_ecc. */ if (this->page256) { if (!(ofs & 0x8)) ofs += 0x100; else ofs -= 0x8; } /* issue the Serial Data In command to initial the Page Program process */ DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0); /* treat crossing 8-byte OOB data for 2M x 8bit devices */ /* Note: datasheet says it should automaticaly wrap to the */ /* next OOB block, but it didn't work here. mf. */ if (this->page256 && ofs + len > (ofs | 0x7) + 1) { len256 = (ofs | 0x7) + 1 - ofs; DoC_WriteBuf(this, buf, len256); DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, 0); /* DoC_WaitReady() is implicit in DoC_Command */ if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error programming oob data\n"); /* There was an error */ *retlen = 0; return -EIO; } DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0); } DoC_WriteBuf(this, &buf[len256], len - len256); DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, 0); /* DoC_WaitReady() is implicit in DoC_Command */ if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error programming oob data\n"); /* There was an error */ *retlen = 0; return -EIO; } *retlen = len; return 0;} static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t * retlen, const u_char * buf){ struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; int ret; down(&this->lock); ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf); up(&this->lock); return ret;}static int doc_erase(struct mtd_info *mtd, struct erase_info *instr){ struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; __u32 ofs = instr->addr; __u32 len = instr->len; volatile int dummy; unsigned long docptr; struct Nand *mychip; int status; down(&this->lock); if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) { up(&this->lock); return -EINVAL; } instr->state = MTD_ERASING; docptr = this->virtadr; /* FIXME: Do this in the background. Use timers or schedule_task() */ while(len) { mychip = &this->chips[ofs >> this->chipshift]; if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; DoC_Command(this, NAND_CMD_ERASE1, 0); DoC_Address(this, ADDR_PAGE, ofs, 0, 0); DoC_Command(this, NAND_CMD_ERASE2, 0); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error erasing at 0x%x\n", ofs); /* There was an error */ instr->state = MTD_ERASE_FAILED; goto callback; } ofs += mtd->erasesize; len -= mtd->erasesize; } instr->state = MTD_ERASE_DONE; callback: mtd_erase_callback(instr); up(&this->lock); return 0;}/**************************************************************************** * * Module stuff * ****************************************************************************/int __init init_doc2000(void){ inter_module_register(im_name, THIS_MODULE, &DoC2k_init); return 0;}static void __exit cleanup_doc2000(void){ struct mtd_info *mtd; struct DiskOnChip *this; while ((mtd = doc2klist)) { this = (struct DiskOnChip *) mtd->priv; doc2klist = this->nextdoc; del_mtd_device(mtd); iounmap((void *) this->virtadr); kfree(this->chips); kfree(mtd); } inter_module_unregister(im_name);}module_exit(cleanup_doc2000);module_init(init_doc2000);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");MODULE_DESCRIPTION("MTD driver for DiskOnChip 2000 and Millennium");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -