fix the newline problem using dos2unix
authoryajin <yajin@vm-kernel.org>
Thu, 15 Jan 2009 19:59:28 +0000 (16 03:59 +0800)
committeryajin <yajin@vm-kernel.org>
Thu, 15 Jan 2009 19:59:28 +0000 (16 03:59 +0800)
hw/nand_bpage.c

index fe1c09f..1cde22c 100755 (executable)
-/*\r
- * Big page NAND flash memory emulation.  based on 256M/16 bit flash datasheet from micro(MT29F2G16ABC)\r
- *\r
- * Copyright (C) 2008 yajin(yajin@vm-kernel.org)\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License as\r
- * published by the Free Software Foundation; either version 2 or\r
- * (at your option) version 3 of the License.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,\r
- * MA 02111-1307 USA\r
- */\r
-\r
-#include "hw.h"\r
-#include "flash.h"\r
-#include "block.h"\r
-#include "sysemu.h"\r
-\r
-\r
-#define MAX_PAGE               0x800\r
-#define MAX_OOB                0x40\r
-#define PAGE_MASK              (0xffff)\r
-#define BUS_WIDTH_16  2\r
-#define BUS_WIDTH_8 1\r
-\r
-//#define DEBUG\r
-\r
-struct nand_flash_info_s\r
-{\r
-    uint8_t  manf_id,chip_id;\r
-    uint32_t size;;\r
-    int bus_width;\r
-    int page_shift;\r
-    int oob_shift;\r
-    int block_shift;\r
-};\r
-\r
-struct nand_flash_info_s nand_flash_info[2] =\r
-{\r
-    {0x2c, 0xba, 256,2, 11, 6, 6},\r
-    {0Xec, 0xd3, 128,1, 11, 6, 6}\r
-};\r
-\r
-\r
-struct nand_bflash_s\r
-{\r
-       BlockDriverState *bdrv;\r
-    uint8_t manf_id, chip_id;\r
-    uint32_t size, pages;\r
-    uint32_t page_size, page_shift;\r
-    uint32_t oob_size, oob_shift;\r
-    uint32_t page_oob_size;\r
-    uint32_t page_sectors;      /*sector = 512 bytes */\r
-    uint32_t block_shift, block_pages;  /*how many pages in a block */\r
-    uint32_t bus_width;         /*bytes */\r
-\r
-    //uint8_t *internal_buf;\r
-    uint8_t io[MAX_PAGE + MAX_OOB + 0x400];\r
-    uint8_t *ioaddr;\r
-    int iolen;\r
-\r
-\r
-    uint32 addr_low, addr_high;\r
-    uint32 addr_cycle;\r
-\r
-    uint32 cmd, status;\r
-  #ifdef DEBUG  \r
-    FILE *fp;\r
-  #endif\r
-};\r
-\r
-\r
-#ifdef DEBUG\r
-static void debug_init(struct nand_bflash_s *s)\r
-{\r
-       s->fp=fopen("nandflash_debug.txt","w+");\r
-       if (s->fp==NULL)\r
-       {\r
-               fprintf(stderr,"can not open nandflash_debug.txt \n");\r
-               exit(-1);\r
-       }\r
-               \r
-}\r
-static void debug_out(struct nand_bflash_s *s,const char* format, ...)\r
-{\r
-       va_list ap;\r
-       if (s->fp)\r
-       {\r
-                va_start(ap, format);\r
-        vfprintf(s->fp, format, ap);\r
-        fflush(s->fp);\r
-       va_end(ap);\r
-       }\r
-}\r
-\r
-#else\r
-static void debug_init(struct nand_bflash_s *s)\r
-{\r
-       \r
-}\r
-static void debug_out(struct nand_bflash_s *s,const char* format, ...)\r
-{\r
-       \r
-}\r
-\r
-#endif\r
-\r
-static inline uint32_t get_page_number(struct nand_bflash_s *s,\r
-                                       uint32_t addr_low, uint32 addr_high)\r
-{\r
-    return (addr_high << 16) + ((addr_low >> 16) & PAGE_MASK);\r
-}\r
-\r
-\r
-\r
-/* Program a single page */\r
-static void nand_blk_write(struct nand_bflash_s *s)\r
-{\r
-    uint32_t page_number, off,  sector, soff;\r
-    uint8_t *iobuf=NULL;\r
-\r
-       if (!iobuf)\r
-       iobuf = qemu_mallocz((s->page_sectors + 2) * 0x200);\r
-    if (!iobuf)\r
-    {\r
-        fprintf(stderr, "can not alloc io buffer size 0x%x \n",\r
-                (s->page_sectors + 2) * 0x200);\r
-        cpu_abort(cpu_single_env, "%s: can not alloc io buffer size 0x%x \n",\r
-                  __FUNCTION__, (s->page_sectors + 2) * 0x200);\r
-    }\r
-\r
-    page_number = get_page_number(s, s->addr_low, s->addr_high);\r
-\r
-    debug_out(s,"nand_blk_write page number %x s->addr_low %x s->addr_high %x\n",page_number,s->addr_low,s->addr_high);\r
-\r
-    if (page_number >= s->pages)\r
-        return;\r
-\r
-    off = page_number * s->page_oob_size + (s->addr_low & PAGE_MASK);\r
-    sector = off >> 9;\r
-    soff = off & 0x1ff;\r
-    if (bdrv_read(s->bdrv, sector, iobuf, s->page_sectors + 2) == -1)\r
-    {\r
-        printf("%s: read error in sector %i\n", __FUNCTION__, sector);\r
-        return;\r
-    }\r
-\r
-    memcpy(iobuf + soff, s->io, s->iolen);\r
-\r
-    if (bdrv_write(s->bdrv, sector, iobuf, s->page_sectors + 2) == -1)\r
-        printf("%s: write error in sector %i\n", __FUNCTION__, sector);\r
-\r
-    //qemu_free(iobuf);\r
-}\r
-\r
-\r
-static void nandb_blk_load(struct nand_bflash_s *s)\r
-{\r
-    uint32_t page_number, offset;\r
-    offset = s->addr_low & PAGE_MASK;\r
-\r
-    page_number = get_page_number(s, s->addr_low, s->addr_high);\r
-       debug_out(s,"nandb_blk_load page number %x s->addr_low %x s->addr_high %x\n",page_number,s->addr_low,s->addr_high);\r
-    if (page_number >= s->pages)\r
-        return;\r
-       \r
-    if (bdrv_read(s->bdrv, (page_number * s->page_oob_size + offset) >> 9,\r
-                  s->io, (s->page_sectors + 2)) == -1)\r
-        printf("%s: read error in sector %i\n",\r
-               __FUNCTION__, page_number * s->page_oob_size);\r
-    s->ioaddr = s->io + ((page_number * s->page_oob_size + offset) & 0x1ff);\r
-}\r
-\r
-\r
-/* Erase a single block */\r
-static void nandb_blk_erase(struct nand_bflash_s *s)\r
-{\r
-    uint32_t page_number,  sector, addr, i;\r
-\r
-    uint8_t iobuf[0x200];\r
-\r
-        memset(iobuf,0xff,sizeof(iobuf));\r
-        s->addr_low = s->addr_low & ~((1 << (16 + s->block_shift)) - 1);\r
-    page_number = get_page_number(s, s->addr_low, s->addr_high);\r
-    debug_out(s,"nandb_blk_erase page number %x s->addr_low %x s->addr_high %x\n",page_number,s->addr_low,s->addr_high);\r
-    if (page_number >= s->pages)\r
-        return;\r
-\r
-    addr = page_number * s->page_oob_size;\r
-    \r
-    sector = addr >> 9;\r
-    if (bdrv_read(s->bdrv, sector, iobuf, 1) == -1)\r
-        printf("%s: read error in sector %i\n", __FUNCTION__, sector);\r
-    memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);\r
-    if (bdrv_write(s->bdrv, sector, iobuf, 1) == -1)\r
-        printf("%s: write error in sector %i\n", __FUNCTION__, sector);\r
-\r
-    memset(iobuf, 0xff, 0x200);\r
-    i = (addr & ~0x1ff) + 0x200;\r
-    for (addr += (s->page_oob_size*s->block_pages - 0x200); i < addr; i += 0x200)\r
-        if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)\r
-            printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);\r
-\r
-    sector = i >> 9;\r
-    if (bdrv_read(s->bdrv, sector, iobuf, 1) == -1)\r
-        printf("%s: read error in sector %i\n", __FUNCTION__, sector);\r
-    memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);\r
-    if (bdrv_write(s->bdrv, sector, iobuf, 1) == -1)\r
-        printf("%s: write error in sector %i\n", __FUNCTION__, sector);\r
-}\r
-\r
-static void nandb_next_page(struct nand_bflash_s *s)\r
-{\r
-    if ((s->addr_low + 0x10000) < s->addr_low)\r
-        s->addr_high++;\r
-    s->addr_low += 0x10000;\r
-}\r
-\r
-void nandb_write_command(struct nand_bflash_s *s, uint16_t value)\r
-{\r
-    int id_index[5] = { 0, 1, 2, 3,4};\r
-\r
-    debug_out(s,"nandb_write_command %x\n",value);\r
-\r
-    switch (value)\r
-    {\r
-    case 0x00:\r
-    case 0x05:\r
-        s->iolen = 0;\r
-        s->addr_cycle = 0;\r
-        break;\r
-    case 0x60:\r
-       /*earse only need 3 addrss cycle.Its address is block address*/\r
-       s->addr_low &= ~PAGE_MASK;\r
-       s->addr_high =0;\r
-       s->addr_cycle = 2;\r
-       break;\r
-    case 0x30:\r
-    case 0xe0:\r
-        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);\r
-        nandb_blk_load(s);\r
-        break;\r
-    case 0x31:\r
-    case 0x3f:\r
-        nandb_next_page(s);\r
-        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);\r
-        nandb_blk_load(s);\r
-        break;\r
-    case 0x90:\r
-        s->iolen = 5 * s->bus_width;\r
-        memset(s->io, 0x0, s->iolen);\r
-        if (s->bus_width == BUS_WIDTH_16)\r
-        {\r
-            id_index[0] = 0;\r
-            id_index[1] = 2;\r
-            id_index[2] = 4;\r
-            id_index[3] = 6;\r
-            id_index[4] = 6;\r
-        }\r
-        s->io[id_index[0]] = s->manf_id;\r
-        s->io[id_index[1]] = s->chip_id;\r
-        s->io[id_index[2]] = 'Q';       /* Don't-care byte (often 0xa5) */\r
-        if ((s->manf_id == NAND_MFR_MICRON) && (s->chip_id == 0xba))\r
-            s->io[id_index[3]] = 0x55;\r
-       if ((s->manf_id == NAND_MFR_SAMSUNG) && (s->chip_id == 0xd3))\r
-       {\r
-               s->io[id_index[3]] = 0x95;\r
-               s->io[id_index[4]] = 0x48;\r
-       }\r
-        s->ioaddr = s->io;\r
-        s->addr_cycle = 0;\r
-        break;\r
-    case 0x70:\r
-        if ((s->manf_id == NAND_MFR_MICRON) && (s->chip_id == 0xba))\r
-        {\r
-            s->status |= 0x60;  /*flash is ready */\r
-            s->status |= 0x80;  /*not protect */\r
-        }\r
-         if ((s->manf_id == NAND_MFR_SAMSUNG) && (s->chip_id == 0xd3))\r
-        {\r
-            s->status |= 0x40;  /*flash is ready */\r
-            s->status |= 0x80;  /*not protect */\r
-        }\r
-        s->io[0] = s->status;\r
-        s->ioaddr = s->io;\r
-        s->iolen = 1;\r
-        break;\r
-    case 0xd0:\r
-        nandb_blk_erase(s);\r
-        break;\r
-    case 0x80:\r
-    case 0x85:\r
-       s->addr_cycle = 0;\r
-       s->ioaddr = s->io;\r
-       s->iolen = 0;\r
-        break;\r
-    case 0x10:\r
-        nand_blk_write(s);\r
-        break;\r
-    case 0xff:\r
-       s->addr_cycle =0;\r
-       s->iolen=0;\r
-       s->addr_low =0;\r
-       s->addr_high =0;\r
-       s->ioaddr = NULL;\r
-       break;\r
-    default:\r
-        fprintf(stderr, "unknown nand command 0x%x \n", value);\r
-        exit(-1);\r
-    }\r
-    s->cmd = value;\r
-}\r
-\r
-void nandb_write_address(struct nand_bflash_s *s, uint16_t value)\r
-{\r
-    uint32_t mask;\r
-    uint32_t colum_addr;\r
-    //if (s->cmd==0x60)\r
-    debug_out(s,"value %x addr_cycle %x \n",value,s->addr_cycle);\r
-    if (s->addr_cycle < 5)\r
-    {\r
-        if (s->addr_cycle < 4)\r
-        {\r
-            mask = ~(0xff << (s->addr_cycle * 8));\r
-            s->addr_low &= mask;\r
-            s->addr_low |= value << (s->addr_cycle * 8);\r
-        }\r
-        else\r
-        {\r
-                         mask = ~(0xff << ((s->addr_cycle-4) * 8));\r
-            s->addr_high &= mask;\r
-            s->addr_high |= value << ((s->addr_cycle-4) * 8);\r
-        }\r
-    }\r
-    else\r
-    {\r
-       fprintf(stderr,"%s wrong addr cycle\n",__FUNCTION__);\r
-       exit(-1);\r
-    }\r
-    if ((s->addr_cycle==1)&&(s->bus_width!=1))\r
-    {\r
-       colum_addr = s->addr_low & PAGE_MASK;\r
-       colum_addr *= s->bus_width;\r
-       s->addr_low &= ~PAGE_MASK;\r
-       s->addr_low += colum_addr;\r
-    }\r
-    s->addr_cycle++;\r
-    \r
-}\r
-\r
-uint8_t nandb_read_data8(struct nand_bflash_s *s)\r
-{\r
-       uint8_t ret;\r
-       if ((s->iolen==0)&&(s->cmd==0x31))\r
-       {\r
-               nandb_next_page(s);\r
-        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);\r
-        nandb_blk_load(s);\r
-       }\r
-       if (s->iolen <= 0)\r
-       {\r
-               fprintf(stderr,"iolen <0 \n");\r
-               exit(-1);\r
-       }\r
-       if (s->cmd!=0x70)       \r
-       s->iolen -=1 ;\r
-    ret = *((uint8_t *)s->ioaddr);\r
-    if (s->cmd!=0x70)          \r
-       s->ioaddr += 1;   \r
-\r
-    //debug_out(s," %x ",ret);\r
-    return ret;\r
-}\r
-\r
-void nandb_write_data8(struct nand_bflash_s *s, uint8_t value)\r
-{\r
-        if ((s->cmd == 0x80) )\r
-        {\r
-        if (s->iolen < s->page_oob_size)\r
-        {\r
-               s->io[s->iolen ++] = value&0xff;\r
-        }\r
-    }\r
-}\r
-\r
-uint16_t nandb_read_data16(struct nand_bflash_s *s)\r
-{\r
-       uint16_t ret;\r
-       if ((s->iolen==0)&&(s->cmd==0x31))\r
-       {\r
-               nandb_next_page(s);\r
-        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);\r
-        nandb_blk_load(s);\r
-       }\r
-       if (s->iolen <= 0)\r
-       {\r
-               fprintf(stderr,"iolen <0 \n");\r
-               exit(-1);\r
-       }\r
-       if (s->cmd!=0x70)       \r
-       s->iolen -=2 ;\r
-    ret = *((uint16_t *)s->ioaddr);\r
-    if (s->cmd!=0x70)          \r
-       s->ioaddr += 2;         \r
-    return ret;\r
-}\r
-\r
-void nandb_write_data16(struct nand_bflash_s *s, uint16_t value)\r
-{\r
-        if ((s->cmd == 0x80) )\r
-        {\r
-        if (s->iolen < s->page_oob_size)\r
-        {\r
-               s->io[s->iolen ++] = value&0xff;\r
-               s->io[s->iolen ++] = (value>>8)&0xff;\r
-        }\r
-    }\r
-}\r
-\r
-struct nand_bflash_s *nandb_init(int manf_id, int chip_id)\r
-{\r
-    //int pagesize;\r
-    struct nand_bflash_s *s;\r
-    int index;\r
-    int i;\r
-\r
-    s = (struct nand_bflash_s *) qemu_mallocz(sizeof(struct nand_bflash_s));\r
-    for (i = 0; i < sizeof(nand_flash_info); i++)\r
-    {\r
-        if ((nand_flash_info[i].manf_id == manf_id)\r
-            && (nand_flash_info[i].chip_id == chip_id))\r
-        {\r
-            s->manf_id = manf_id;\r
-            s->chip_id = chip_id;\r
-            s->page_shift = nand_flash_info[i].page_shift;\r
-            s->oob_shift = nand_flash_info[i].oob_shift;\r
-            s->bus_width = nand_flash_info[i].bus_width;\r
-            s->page_size = 1 << s->page_shift;\r
-            s->oob_size = 1 << s->oob_shift;\r
-            s->block_shift = nand_flash_info[i].block_shift;\r
-            s->block_pages = 1 << s->block_shift;\r
-            s->page_oob_size = s->page_size + s->oob_size;\r
-            s->page_sectors = 1 << (s->page_shift - 9);\r
-            /*TODO: size overflow */\r
-            s->size = nand_flash_info[i].size << 20;\r
-            s->pages = (s->size / s->page_size);\r
-\r
-            break;\r
-        }\r
-\r
-    }\r
-    if (i >= sizeof(nand_flash_info))\r
-    {\r
-        fprintf(stderr, "%s: Unsupported NAND chip ID.\n",\r
-                  __FUNCTION__);\r
-        exit(-1);\r
-    }\r
-\r
-    \r
-    index = drive_get_index(IF_MTD, 0, 0);\r
-    if (index != -1)\r
-        s->bdrv = drives_table[index].bdrv;\r
-    else\r
-    {\r
-       fprintf(stderr, "%s: Please use -mtdblock to specify flash image.\n",\r
-                  __FUNCTION__);\r
-        exit(-1);\r
-    }\r
-\r
-    if (bdrv_getlength(s->bdrv) != (s->pages*s->page_oob_size))\r
-    {\r
-       fprintf(stderr,  "%s: Invalid flash image size.\n",\r
-                  __FUNCTION__);\r
-        exit(-1);\r
-\r
-    }\r
-\r
-       debug_init(s);\r
-    return s;\r
-\r
-}\r
-\r
+/*
+ * Big page NAND flash memory emulation.  based on 256M/16 bit flash datasheet from micro(MT29F2G16ABC)
+ *
+ * Copyright (C) 2008 yajin(yajin@vm-kernel.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "hw.h"
+#include "flash.h"
+#include "block.h"
+#include "sysemu.h"
+
+
+#define MAX_PAGE               0x800
+#define MAX_OOB                0x40
+#define PAGE_MASK              (0xffff)
+#define BUS_WIDTH_16  2
+#define BUS_WIDTH_8 1
+
+//#define DEBUG
+
+struct nand_flash_info_s
+{
+    uint8_t  manf_id,chip_id;
+    uint32_t size;;
+    int bus_width;
+    int page_shift;
+    int oob_shift;
+    int block_shift;
+};
+
+struct nand_flash_info_s nand_flash_info[2] =
+{
+    {0x2c, 0xba, 256,2, 11, 6, 6},
+    {0Xec, 0xd3, 128,1, 11, 6, 6}
+};
+
+
+struct nand_bflash_s
+{
+       BlockDriverState *bdrv;
+    uint8_t manf_id, chip_id;
+    uint32_t size, pages;
+    uint32_t page_size, page_shift;
+    uint32_t oob_size, oob_shift;
+    uint32_t page_oob_size;
+    uint32_t page_sectors;      /*sector = 512 bytes */
+    uint32_t block_shift, block_pages;  /*how many pages in a block */
+    uint32_t bus_width;         /*bytes */
+
+    //uint8_t *internal_buf;
+    uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
+    uint8_t *ioaddr;
+    int iolen;
+
+
+    uint32 addr_low, addr_high;
+    uint32 addr_cycle;
+
+    uint32 cmd, status;
+  #ifdef DEBUG  
+    FILE *fp;
+  #endif
+};
+
+
+#ifdef DEBUG
+static void debug_init(struct nand_bflash_s *s)
+{
+       s->fp=fopen("nandflash_debug.txt","w+");
+       if (s->fp==NULL)
+       {
+               fprintf(stderr,"can not open nandflash_debug.txt \n");
+               exit(-1);
+       }
+               
+}
+static void debug_out(struct nand_bflash_s *s,const char* format, ...)
+{
+       va_list ap;
+       if (s->fp)
+       {
+                va_start(ap, format);
+        vfprintf(s->fp, format, ap);
+        fflush(s->fp);
+       va_end(ap);
+       }
+}
+
+#else
+static void debug_init(struct nand_bflash_s *s)
+{
+       
+}
+static void debug_out(struct nand_bflash_s *s,const char* format, ...)
+{
+       
+}
+
+#endif
+
+static inline uint32_t get_page_number(struct nand_bflash_s *s,
+                                       uint32_t addr_low, uint32 addr_high)
+{
+    return (addr_high << 16) + ((addr_low >> 16) & PAGE_MASK);
+}
+
+
+
+/* Program a single page */
+static void nand_blk_write(struct nand_bflash_s *s)
+{
+    uint32_t page_number, off,  sector, soff;
+    uint8_t *iobuf=NULL;
+
+       if (!iobuf)
+       iobuf = qemu_mallocz((s->page_sectors + 2) * 0x200);
+    if (!iobuf)
+    {
+        fprintf(stderr, "can not alloc io buffer size 0x%x \n",
+                (s->page_sectors + 2) * 0x200);
+        cpu_abort(cpu_single_env, "%s: can not alloc io buffer size 0x%x \n",
+                  __FUNCTION__, (s->page_sectors + 2) * 0x200);
+    }
+
+    page_number = get_page_number(s, s->addr_low, s->addr_high);
+
+    debug_out(s,"nand_blk_write page number %x s->addr_low %x s->addr_high %x\n",page_number,s->addr_low,s->addr_high);
+
+    if (page_number >= s->pages)
+        return;
+
+    off = page_number * s->page_oob_size + (s->addr_low & PAGE_MASK);
+    sector = off >> 9;
+    soff = off & 0x1ff;
+    if (bdrv_read(s->bdrv, sector, iobuf, s->page_sectors + 2) == -1)
+    {
+        printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+        return;
+    }
+
+    memcpy(iobuf + soff, s->io, s->iolen);
+
+    if (bdrv_write(s->bdrv, sector, iobuf, s->page_sectors + 2) == -1)
+        printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+
+    //qemu_free(iobuf);
+}
+
+
+static void nandb_blk_load(struct nand_bflash_s *s)
+{
+    uint32_t page_number, offset;
+    offset = s->addr_low & PAGE_MASK;
+
+    page_number = get_page_number(s, s->addr_low, s->addr_high);
+       debug_out(s,"nandb_blk_load page number %x s->addr_low %x s->addr_high %x\n",page_number,s->addr_low,s->addr_high);
+    if (page_number >= s->pages)
+        return;
+       
+    if (bdrv_read(s->bdrv, (page_number * s->page_oob_size + offset) >> 9,
+                  s->io, (s->page_sectors + 2)) == -1)
+        printf("%s: read error in sector %i\n",
+               __FUNCTION__, page_number * s->page_oob_size);
+    s->ioaddr = s->io + ((page_number * s->page_oob_size + offset) & 0x1ff);
+}
+
+
+/* Erase a single block */
+static void nandb_blk_erase(struct nand_bflash_s *s)
+{
+    uint32_t page_number,  sector, addr, i;
+
+    uint8_t iobuf[0x200];
+
+        memset(iobuf,0xff,sizeof(iobuf));
+        s->addr_low = s->addr_low & ~((1 << (16 + s->block_shift)) - 1);
+    page_number = get_page_number(s, s->addr_low, s->addr_high);
+    debug_out(s,"nandb_blk_erase page number %x s->addr_low %x s->addr_high %x\n",page_number,s->addr_low,s->addr_high);
+    if (page_number >= s->pages)
+        return;
+
+    addr = page_number * s->page_oob_size;
+    
+    sector = addr >> 9;
+    if (bdrv_read(s->bdrv, sector, iobuf, 1) == -1)
+        printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+    memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
+    if (bdrv_write(s->bdrv, sector, iobuf, 1) == -1)
+        printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+
+    memset(iobuf, 0xff, 0x200);
+    i = (addr & ~0x1ff) + 0x200;
+    for (addr += (s->page_oob_size*s->block_pages - 0x200); i < addr; i += 0x200)
+        if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+
+    sector = i >> 9;
+    if (bdrv_read(s->bdrv, sector, iobuf, 1) == -1)
+        printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+    memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
+    if (bdrv_write(s->bdrv, sector, iobuf, 1) == -1)
+        printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+}
+
+static void nandb_next_page(struct nand_bflash_s *s)
+{
+    if ((s->addr_low + 0x10000) < s->addr_low)
+        s->addr_high++;
+    s->addr_low += 0x10000;
+}
+
+void nandb_write_command(struct nand_bflash_s *s, uint16_t value)
+{
+    int id_index[5] = { 0, 1, 2, 3,4};
+
+    debug_out(s,"nandb_write_command %x\n",value);
+
+    switch (value)
+    {
+    case 0x00:
+    case 0x05:
+        s->iolen = 0;
+        s->addr_cycle = 0;
+        break;
+    case 0x60:
+       /*earse only need 3 addrss cycle.Its address is block address*/
+       s->addr_low &= ~PAGE_MASK;
+       s->addr_high =0;
+       s->addr_cycle = 2;
+       break;
+    case 0x30:
+    case 0xe0:
+        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
+        nandb_blk_load(s);
+        break;
+    case 0x31:
+    case 0x3f:
+        nandb_next_page(s);
+        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
+        nandb_blk_load(s);
+        break;
+    case 0x90:
+        s->iolen = 5 * s->bus_width;
+        memset(s->io, 0x0, s->iolen);
+        if (s->bus_width == BUS_WIDTH_16)
+        {
+            id_index[0] = 0;
+            id_index[1] = 2;
+            id_index[2] = 4;
+            id_index[3] = 6;
+            id_index[4] = 6;
+        }
+        s->io[id_index[0]] = s->manf_id;
+        s->io[id_index[1]] = s->chip_id;
+        s->io[id_index[2]] = 'Q';       /* Don't-care byte (often 0xa5) */
+        if ((s->manf_id == NAND_MFR_MICRON) && (s->chip_id == 0xba))
+            s->io[id_index[3]] = 0x55;
+       if ((s->manf_id == NAND_MFR_SAMSUNG) && (s->chip_id == 0xd3))
+       {
+               s->io[id_index[3]] = 0x95;
+               s->io[id_index[4]] = 0x48;
+       }
+        s->ioaddr = s->io;
+        s->addr_cycle = 0;
+        break;
+    case 0x70:
+        if ((s->manf_id == NAND_MFR_MICRON) && (s->chip_id == 0xba))
+        {
+            s->status |= 0x60;  /*flash is ready */
+            s->status |= 0x80;  /*not protect */
+        }
+         if ((s->manf_id == NAND_MFR_SAMSUNG) && (s->chip_id == 0xd3))
+        {
+            s->status |= 0x40;  /*flash is ready */
+            s->status |= 0x80;  /*not protect */
+        }
+        s->io[0] = s->status;
+        s->ioaddr = s->io;
+        s->iolen = 1;
+        break;
+    case 0xd0:
+        nandb_blk_erase(s);
+        break;
+    case 0x80:
+    case 0x85:
+       s->addr_cycle = 0;
+       s->ioaddr = s->io;
+       s->iolen = 0;
+        break;
+    case 0x10:
+        nand_blk_write(s);
+        break;
+    case 0xff:
+       s->addr_cycle =0;
+       s->iolen=0;
+       s->addr_low =0;
+       s->addr_high =0;
+       s->ioaddr = NULL;
+       break;
+    default:
+        fprintf(stderr, "unknown nand command 0x%x \n", value);
+        exit(-1);
+    }
+    s->cmd = value;
+}
+
+void nandb_write_address(struct nand_bflash_s *s, uint16_t value)
+{
+    uint32_t mask;
+    uint32_t colum_addr;
+    //if (s->cmd==0x60)
+    debug_out(s,"value %x addr_cycle %x \n",value,s->addr_cycle);
+    if (s->addr_cycle < 5)
+    {
+        if (s->addr_cycle < 4)
+        {
+            mask = ~(0xff << (s->addr_cycle * 8));
+            s->addr_low &= mask;
+            s->addr_low |= value << (s->addr_cycle * 8);
+        }
+        else
+        {
+                         mask = ~(0xff << ((s->addr_cycle-4) * 8));
+            s->addr_high &= mask;
+            s->addr_high |= value << ((s->addr_cycle-4) * 8);
+        }
+    }
+    else
+    {
+       fprintf(stderr,"%s wrong addr cycle\n",__FUNCTION__);
+       exit(-1);
+    }
+    if ((s->addr_cycle==1)&&(s->bus_width!=1))
+    {
+       colum_addr = s->addr_low & PAGE_MASK;
+       colum_addr *= s->bus_width;
+       s->addr_low &= ~PAGE_MASK;
+       s->addr_low += colum_addr;
+    }
+    s->addr_cycle++;
+    
+}
+
+uint8_t nandb_read_data8(struct nand_bflash_s *s)
+{
+       uint8_t ret;
+       if ((s->iolen==0)&&(s->cmd==0x31))
+       {
+               nandb_next_page(s);
+        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
+        nandb_blk_load(s);
+       }
+       if (s->iolen <= 0)
+       {
+               fprintf(stderr,"iolen <0 \n");
+               exit(-1);
+       }
+       if (s->cmd!=0x70)       
+       s->iolen -=1 ;
+    ret = *((uint8_t *)s->ioaddr);
+    if (s->cmd!=0x70)          
+       s->ioaddr += 1;   
+
+    //debug_out(s," %x ",ret);
+    return ret;
+}
+
+void nandb_write_data8(struct nand_bflash_s *s, uint8_t value)
+{
+        if ((s->cmd == 0x80) )
+        {
+        if (s->iolen < s->page_oob_size)
+        {
+               s->io[s->iolen ++] = value&0xff;
+        }
+    }
+}
+
+uint16_t nandb_read_data16(struct nand_bflash_s *s)
+{
+       uint16_t ret;
+       if ((s->iolen==0)&&(s->cmd==0x31))
+       {
+               nandb_next_page(s);
+        s->iolen = s->page_oob_size - (s->addr_low & PAGE_MASK);
+        nandb_blk_load(s);
+       }
+       if (s->iolen <= 0)
+       {
+               fprintf(stderr,"iolen <0 \n");
+               exit(-1);
+       }
+       if (s->cmd!=0x70)       
+       s->iolen -=2 ;
+    ret = *((uint16_t *)s->ioaddr);
+    if (s->cmd!=0x70)          
+       s->ioaddr += 2;         
+    return ret;
+}
+
+void nandb_write_data16(struct nand_bflash_s *s, uint16_t value)
+{
+        if ((s->cmd == 0x80) )
+        {
+        if (s->iolen < s->page_oob_size)
+        {
+               s->io[s->iolen ++] = value&0xff;
+               s->io[s->iolen ++] = (value>>8)&0xff;
+        }
+    }
+}
+
+struct nand_bflash_s *nandb_init(int manf_id, int chip_id)
+{
+    //int pagesize;
+    struct nand_bflash_s *s;
+    int index;
+    int i;
+
+    s = (struct nand_bflash_s *) qemu_mallocz(sizeof(struct nand_bflash_s));
+    for (i = 0; i < sizeof(nand_flash_info); i++)
+    {
+        if ((nand_flash_info[i].manf_id == manf_id)
+            && (nand_flash_info[i].chip_id == chip_id))
+        {
+            s->manf_id = manf_id;
+            s->chip_id = chip_id;
+            s->page_shift = nand_flash_info[i].page_shift;
+            s->oob_shift = nand_flash_info[i].oob_shift;
+            s->bus_width = nand_flash_info[i].bus_width;
+            s->page_size = 1 << s->page_shift;
+            s->oob_size = 1 << s->oob_shift;
+            s->block_shift = nand_flash_info[i].block_shift;
+            s->block_pages = 1 << s->block_shift;
+            s->page_oob_size = s->page_size + s->oob_size;
+            s->page_sectors = 1 << (s->page_shift - 9);
+            /*TODO: size overflow */
+            s->size = nand_flash_info[i].size << 20;
+            s->pages = (s->size / s->page_size);
+
+            break;
+        }
+
+    }
+    if (i >= sizeof(nand_flash_info))
+    {
+        fprintf(stderr, "%s: Unsupported NAND chip ID.\n",
+                  __FUNCTION__);
+        exit(-1);
+    }
+
+    
+    index = drive_get_index(IF_MTD, 0, 0);
+    if (index != -1)
+        s->bdrv = drives_table[index].bdrv;
+    else
+    {
+       fprintf(stderr, "%s: Please use -mtdblock to specify flash image.\n",
+                  __FUNCTION__);
+        exit(-1);
+    }
+
+    if (bdrv_getlength(s->bdrv) != (s->pages*s->page_oob_size))
+    {
+       fprintf(stderr,  "%s: Invalid flash image size.\n",
+                  __FUNCTION__);
+        exit(-1);
+
+    }
+
+       debug_init(s);
+    return s;
+
+}
+