diff options
Diffstat (limited to 'fs/yaffs2/mtdemul/nandemul2k.c')
-rw-r--r-- | fs/yaffs2/mtdemul/nandemul2k.c | 714 |
1 files changed, 0 insertions, 714 deletions
diff --git a/fs/yaffs2/mtdemul/nandemul2k.c b/fs/yaffs2/mtdemul/nandemul2k.c deleted file mode 100644 index bcbf16a..0000000 --- a/fs/yaffs2/mtdemul/nandemul2k.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * This version hacked for emulating 2kpage NAND for YAFFS2 testing. - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/fs.h> -#include <linux/proc_fs.h> -#include <linux/pagemap.h> -#include <linux/mtd/mtd.h> -#include <linux/interrupt.h> -#include <linux/string.h> -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -#include <linux/locks.h> -#endif - -#include <asm/uaccess.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/nand.h> -#include "../yaffs_nandemul2k.h" - -#define ALLOCATE(x) kmalloc(x,GFP_KERNEL) -#define FREE(x) kfree(x) - - - - - -#define NAND_SHIFT (11) // Shifter for 2k -#define PAGE_DATA_SIZE (1 << NAND_SHIFT) -#define PAGE_SPARE_SIZE (64) -#define BLK_SHIFT 6 -#define PAGES_PER_BLOCK (1 << BLK_SHIFT) // = 64 - - -#define EM_SIZE_IN_MEG 4 -#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20)) - -#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE) - -#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE) - -#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE)) - - -static struct mtd_info nandemul2k_mtd; - -typedef struct -{ - __u8 data[PAGE_TOTAL_SIZE]; // Data + spare - int empty; // is this empty? -} nandemul_Page; - - -typedef struct -{ - nandemul_Page *page[PAGES_PER_BLOCK]; - int damaged; -} nandemul_Block; - - - -typedef struct -{ - nandemul_Block**block; - int nBlocks; -} nandemul_Device; - -static nandemul_Device ned; - -static int sizeInMB = EM_SIZE_IN_MEG; - - -static void nandemul_yield(int n) -{ -#ifdef __KERNEL__ - if(n > 0) schedule_timeout(n); -#endif - -} - - -static void nandemul2k_Read(void *buffer, int page, int start, int nBytes) -{ - int pg = page%PAGES_PER_BLOCK; - int blk = page/PAGES_PER_BLOCK; - if(buffer && nBytes > 0) - { - memcpy(buffer,&ned.block[blk]->page[pg]->data[start],nBytes); - } - -} - -static void nandemul2k_Program(const void *buffer, int page, int start, int nBytes) -{ - int pg = page%PAGES_PER_BLOCK; - int blk = page/PAGES_PER_BLOCK; - __u8 *p; - __u8 *b = (__u8 *)buffer; - - p = &ned.block[blk]->page[pg]->data[start]; - - while(buffer && nBytes>0) - { - *p = *p & *b; - p++; - b++; - nBytes--; - } -} - -static void nandemul2k_DoErase(int blockNumber) -{ - int i; - - nandemul_Block *blk; - - if(blockNumber < 0 || blockNumber >= ned.nBlocks) - { - return; - } - - blk = ned.block[blockNumber]; - - for(i = 0; i < PAGES_PER_BLOCK; i++) - { - memset(blk->page[i],0xff,sizeof(nandemul_Page)); - blk->page[i]->empty = 1; - } - nandemul_yield(2); -} - - -static int nandemul2k_CalcNBlocks(void) -{ - return EM_SIZE_IN_MEG * BLOCKS_PER_MEG; -} - - - -static int CheckInit(void) -{ - static int initialised = 0; - - int i,j; - - int fail = 0; - int nBlocks; - - int nAllocated = 0; - - if(initialised) - { - return 0; - } - - - ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks(); - - - ned.block = ALLOCATE(sizeof(nandemul_Block*) * nBlocks ); - - if(!ned.block) return ENOMEM; - - - - - - for(i=fail=0; i <nBlocks; i++) - { - - nandemul_Block *blk; - - if(!(blk = ned.block[i] = ALLOCATE(sizeof(nandemul_Block)))) - { - fail = 1; - } - else - { - for(j = 0; j < PAGES_PER_BLOCK; j++) - { - if((blk->page[j] = ALLOCATE(sizeof(nandemul_Page))) == 0) - { - fail = 1; - } - } - nandemul2k_DoErase(i); - ned.block[i]->damaged = 0; - nAllocated++; - } - } - - if(fail) - { - //Todo thump pages - - for(i = 0; i < nAllocated; i++) - { - FREE(ned.block[i]); - } - FREE(ned.block); - - return ENOMEM; - } - - ned.nBlocks = nBlocks; - - initialised = 1; - - return 1; -} - - - -static void nandemul2k_CleanUp(void) -{ - int i,j; - - for(i = 0; i < ned.nBlocks; i++) - { - for(j = 0; j < PAGES_PER_BLOCK; j++) - { - FREE(ned.block[i]->page[j]); - } - FREE(ned.block[i]); - - } - FREE(ned.block); - ned.block = 0; -} - -int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;} - -int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; } -int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();} - - - -static int nandemul2k_ReadId(__u8 *vendorId, __u8 *deviceId) -{ - *vendorId = 'Y'; - *deviceId = '2'; - - return 1; -} - - -static int nandemul2k_ReadStatus(__u8 *status) -{ - *status = 0; - return 1; -} - - -#ifdef CONFIG_MTD_NAND_ECC -#include <linux/mtd/nand_ecc.h> -#endif - -/* - * NAND low-level MTD interface functions - */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *dummy); -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf); -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, - u_char *oob_buf, struct nand_oobinfo *dummy); -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7)) -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen); -#else -static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen); -#endif -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); -static void nand_sync (struct mtd_info *mtd); - - - -/* - * NAND read - */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - return nand_read_ecc (mtd, from, len, retlen, buf, NULL,NULL); -} - - -/* - * NAND read with ECC - */ -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *oob_buf,struct nand_oobinfo *oobsel) -{ - int start, page; - int n = len; - int nToCopy; - - - - /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { - *retlen = 0; - return -EINVAL; - } - - - /* Initialize return value */ - *retlen = 0; - - while(n > 0) - { - - /* First we calculate the starting page */ - page = from >> NAND_SHIFT; - - /* Get raw starting column */ - - start = from & (mtd->oobblock-1); - - // OK now check for the curveball where the start and end are in - // the same page - if((start + n) < mtd->oobblock) - { - nToCopy = n; - } - else - { - nToCopy = mtd->oobblock - start; - } - - nandemul2k_Read(buf, page, start, nToCopy); - nandemul2k_Read(oob_buf,page,PAGE_DATA_SIZE,PAGE_SPARE_SIZE); - - n -= nToCopy; - from += nToCopy; - buf += nToCopy; - if(oob_buf) oob_buf += PAGE_SPARE_SIZE; - *retlen += nToCopy; - - } - - - return 0; -} - -/* - * NAND read out-of-band - */ -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - int col, page; - - T(0,("nand_read_oob: from = 0x%08x, buf = 0x%08x, len = %i\n", (unsigned int) from, (unsigned int) buf, - (int) len)); - - /* Shift to get page */ - page = ((int) from) >> NAND_SHIFT; - - /* Mask to get column */ - col = from & 0x0f; - - /* Initialize return length value */ - *retlen = 0; - - /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { - T(0, - ("nand_read_oob: Attempt read beyond end of device\n")); - *retlen = 0; - return -EINVAL; - } - - nandemul2k_Read(buf,page,PAGE_DATA_SIZE + col,len); - - /* Return happy */ - *retlen = len; - return 0; -} - -/* - * NAND write - */ -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - return nand_write_ecc (mtd, to, len, retlen, buf, NULL,NULL); -} - -/* - * NAND write with ECC - */ -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, - u_char *oob_buf, struct nand_oobinfo *dummy) -{ - - int start, page; - int n = len; - int nToCopy; - - - - /* Do not allow reads past end of device */ - if ((to + len) > mtd->size) { - *retlen = 0; - return -EINVAL; - } - - - /* Initialize return value */ - *retlen = 0; - - while(n > 0) - { - - /* First we calculate the starting page */ - page = to >> NAND_SHIFT; - - /* Get raw starting column */ - - start = to & (mtd->oobblock - 1); - - // OK now check for the curveball where the start and end are in - // the same page - if((start + n) < mtd->oobblock) - { - nToCopy = n; - } - else - { - nToCopy = mtd->oobblock - start; - } - - nandemul2k_Program(buf, page, start, nToCopy); - nandemul2k_Program(oob_buf, page, PAGE_DATA_SIZE, PAGE_SPARE_SIZE); - - n -= nToCopy; - to += nToCopy; - buf += nToCopy; - if(oob_buf) oob_buf += PAGE_SPARE_SIZE; - *retlen += nToCopy; - - } - - - return 0; -} - -/* - * NAND write out-of-band - */ -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - int col, page; - - - T(0,( - "nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to, - (int) len)); - - /* Shift to get page */ - page = ((int) to) >> NAND_SHIFT; - - /* Mask to get column */ - col = to & 0x0f; - - /* Initialize return length value */ - *retlen = 0; - - /* Do not allow reads past end of device */ - if ((to + len) > mtd->size) { - T(0,( - "nand_read_oob: Attempt read beyond end of device\n")); - *retlen = 0; - return -EINVAL; - } - - nandemul2k_Program(buf,page,512 + col,len); - - /* Return happy */ - *retlen = len; - return 0; - -} - -/* - * NAND write with iovec - */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7)) -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen) -#else -static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen) -#endif -{ - return -EINVAL; -} - -/* - * NAND erase a block - */ -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) -{ - int i, nBlocks,block; - - T(0,( - "nand_erase: start = 0x%08x, len = %i\n", - (unsigned int) instr->addr, (unsigned int) instr->len)); - - /* Start address must align on block boundary */ - if (instr->addr & (mtd->erasesize - 1)) { - T(0,( - "nand_erase: Unaligned address\n")); - return -EINVAL; - } - - /* Length must align on block boundary */ - if (instr->len & (mtd->erasesize - 1)) { - T(0,( - "nand_erase: Length not block aligned\n")); - return -EINVAL; - } - - /* Do not allow erase past end of device */ - if ((instr->len + instr->addr) > mtd->size) { - T(0,( - "nand_erase: Erase past end of device\n")); - return -EINVAL; - } - - nBlocks = instr->len >> (NAND_SHIFT + BLK_SHIFT); - block = instr->addr >> (NAND_SHIFT + BLK_SHIFT); - - for(i = 0; i < nBlocks; i++) - { - nandemul2k_DoErase(block); - block++; - } - - instr->state = MTD_ERASE_DONE; * change state to ERASE_DONE */ - - instr->callback(instr); * wake up */ - - return 0; - - -} - - -static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs) -{ - return 0; -} - -static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - return 0; -} - - -/* - * NAND sync - */ -static void nand_sync (struct mtd_info *mtd) -{ - T(0,("nand_sync: called\n")); - -} - -/* - * Scan for the NAND device - */ -static int nandemul2k_scan (struct mtd_info *mtd,int nchips) -{ - mtd->oobblock = PAGE_DATA_SIZE; - mtd->oobsize = PAGE_SPARE_SIZE; - mtd->erasesize = PAGE_DATA_SIZE * PAGES_PER_BLOCK; - mtd->size = sizeInMB * 1024*1024; - - - - /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH; - mtd->owner = THIS_MODULE; - mtd->ecctype = MTD_ECC_NONE; - mtd->erase = nand_erase; - mtd->point = NULL; - mtd->unpoint = NULL; - mtd->read = nand_read; - mtd->write = nand_write; - mtd->read_ecc = nand_read_ecc; - mtd->write_ecc = nand_write_ecc; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; - mtd->block_isbad = nand_block_isbad; - mtd->block_markbad = nand_block_markbad; - mtd->readv = NULL; - mtd->writev = nand_writev; - mtd->sync = nand_sync; - mtd->lock = NULL; - mtd->unlock = NULL; - mtd->suspend = NULL; - mtd->resume = NULL; - - mtd->name = "NANDemul2k"; - - /* Return happy */ - return 0; -} - -#if 0 -#ifdef MODULE -MODULE_PARM(sizeInMB, "i"); - -__setup("sizeInMB=",sizeInMB); -#endif -#endif - -/* - * Define partitions for flash devices - */ - -static struct mtd_partition nandemul2k_partition[] = -{ - { .name = "NANDemul partition 1", - .offset = 0, - .size = 0 }, -}; - -static int nPartitions = sizeof(nandemul2k_partition)/sizeof(nandemul2k_partition[0]); - -/* - * Main initialization routine - */ -int __init nandemul2k_init (void) -{ - - // Do the nand init - - CheckInit(); - - nandemul2k_scan(&nandemul2k_mtd,1); - - // Build the partition table - - nandemul2k_partition[0].size = sizeInMB * 1024 * 1024; - - // Register the partition - add_mtd_partitions(&nandemul2k_mtd,nandemul2k_partition,nPartitions); - - return 0; - -} - -module_init(nandemul2k_init); - -/* - * Clean up routine - */ -#ifdef MODULE -static void __exit nandemul2k_cleanup (void) -{ - - nandemul2k_CleanUp(); - - /* Unregister partitions */ - del_mtd_partitions(&nandemul2k_mtd); - - /* Unregister the device */ - del_mtd_device (&nandemul2k_mtd); - -} -module_exit(nandemul2k_cleanup); -#endif - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>"); -MODULE_DESCRIPTION("2k Page/128k Block NAND emulated in RAM"); - - - - |