]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 18:24:08 +0000 (10:24 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 18:24:08 +0000 (10:24 -0800)
Some manual fixups for clashing kfree() cleanups etc.

22 files changed:
1  2 
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/devices/blkmtd.c
drivers/mtd/inftlcore.c
drivers/mtd/inftlmount.c
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/bast-flash.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/integrator-flash.c
drivers/mtd/maps/ipaq-flash.c
drivers/mtd/maps/iq80310.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/lubbock-flash.c
drivers/mtd/maps/omap-toto-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/maps/tqm8xxl.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nftlcore.c
fs/Kconfig
fs/jffs2/wbuf.c

index c3fc9b2f21fbd5988a39dd2c9c0f12d0fd69190f,e3a5c5d331b43a60e7456a3a5e89b17ecdcdde2b..143f01a4c1705343a2406c53f1aff0f71b4feb28
@@@ -4,9 -4,9 +4,9 @@@
   *
   * (C) 2000 Red Hat. GPL'd
   *
-  * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
+  * $Id: cfi_cmdset_0001.c,v 1.185 2005/11/07 11:14:22 gleixner Exp $
+  *
   *
-  * 
   * 10/10/2000 Nicolas Pitre <nico@cam.org>
   *    - completely revamped method functions so they are aware and
   *      independent of the flash geometry (buswidth, interleave, etc.)
@@@ -51,6 -51,7 +51,7 @@@
  static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
  static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
  static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+ static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
  static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
  static void cfi_intelext_sync (struct mtd_info *);
  static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
@@@ -105,6 -106,7 +106,7 @@@ static struct mtd_chip_driver cfi_intel
  static void cfi_tell_features(struct cfi_pri_intelext *extp)
  {
        int i;
+       printk("  Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion);
        printk("  Feature/Command Support:      %4.4X\n", extp->FeatureSupport);
        printk("     - Chip Erase:              %s\n", extp->FeatureSupport&1?"supported":"unsupported");
        printk("     - Suspend Erase:           %s\n", extp->FeatureSupport&2?"supported":"unsupported");
        printk("     - Page-mode read:          %s\n", extp->FeatureSupport&128?"supported":"unsupported");
        printk("     - Synchronous read:        %s\n", extp->FeatureSupport&256?"supported":"unsupported");
        printk("     - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
-       for (i=10; i<32; i++) {
-               if (extp->FeatureSupport & (1<<i)) 
+       printk("     - Extended Flash Array:    %s\n", extp->FeatureSupport&1024?"supported":"unsupported");
+       for (i=11; i<32; i++) {
+               if (extp->FeatureSupport & (1<<i))
                        printk("     - Unknown Bit %X:      supported\n", i);
        }
-       
        printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
        printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
        for (i=1; i<8; i++) {
                if (extp->SuspendCmdSupport & (1<<i))
                        printk("     - Unknown Bit %X:               supported\n", i);
        }
-       
        printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
        printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
-       printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
-       for (i=2; i<16; i++) {
+       printk("     - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+       for (i=2; i<3; i++) {
                if (extp->BlkStatusRegMask & (1<<i))
                        printk("     - Unknown Bit %X Active: yes\n",i);
        }
-       
-       printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+       printk("     - EFA Lock Bit:         %s\n", extp->BlkStatusRegMask&16?"yes":"no");
+       printk("     - EFA Lock-Down Bit:    %s\n", extp->BlkStatusRegMask&32?"yes":"no");
+       for (i=6; i<16; i++) {
+               if (extp->BlkStatusRegMask & (1<<i))
+                       printk("     - Unknown Bit %X Active: yes\n",i);
+       }
+       printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
               extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
        if (extp->VppOptimal)
-               printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+               printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
                       extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
  }
  #endif
  
  #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
- /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
+ /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
  static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
  {
        struct map_info *map = mtd->priv;
@@@ -176,7 -185,7 +185,7 @@@ static void fixup_st_m28w320ct(struct m
  {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       
        cfi->cfiq->BufWriteTimeoutTyp = 0;      /* Not supported */
        cfi->cfiq->BufWriteTimeoutMax = 0;      /* Not supported */
  }
@@@ -185,7 -194,7 +194,7 @@@ static void fixup_st_m28w320cb(struct m
  {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       
        /* Note this is done after the region info is endian swapped */
        cfi->cfiq->EraseRegionInfo[1] =
                (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
@@@ -207,12 -216,13 +216,13 @@@ static void fixup_use_write_buffers(str
        if (cfi->cfiq->BufWriteTimeoutTyp) {
                printk(KERN_INFO "Using buffer write method\n" );
                mtd->write = cfi_intelext_write_buffers;
+               mtd->writev = cfi_intelext_writev;
        }
  }
  
  static struct cfi_fixup cfi_fixup_table[] = {
  #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, 
+       { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
  #endif
  #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL },
@@@ -252,12 -262,21 +262,21 @@@ read_pri_intelext(struct map_info *map
        if (!extp)
                return NULL;
  
+       if (extp->MajorVersion != '1' ||
+           (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+               printk(KERN_ERR "  Unknown Intel/Sharp Extended Query "
+                      "version %c.%c.\n",  extp->MajorVersion,
+                      extp->MinorVersion);
+               kfree(extp);
+               return NULL;
+       }
        /* Do some byteswapping if necessary */
        extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
        extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
        extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
  
-       if (extp->MajorVersion == '1' && extp->MinorVersion == '3') {
+       if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') {
                unsigned int extra_size = 0;
                int nb_parts, i;
  
                              sizeof(struct cfi_intelext_otpinfo);
  
                /* Burst Read info */
-               extra_size += 6;
+               extra_size += 2;
+               if (extp_size < sizeof(*extp) + extra_size)
+                       goto need_more;
+               extra_size += extp->extra[extra_size-1];
  
                /* Number of hardware-partitions */
                extra_size += 1;
                        goto need_more;
                nb_parts = extp->extra[extra_size - 1];
  
+               /* skip the sizeof(partregion) field in CFI 1.4 */
+               if (extp->MinorVersion >= '4')
+                       extra_size += 2;
                for (i = 0; i < nb_parts; i++) {
                        struct cfi_intelext_regioninfo *rinfo;
                        rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
                                      * sizeof(struct cfi_intelext_blockinfo);
                }
  
+               if (extp->MinorVersion >= '4')
+                       extra_size += sizeof(struct cfi_intelext_programming_regioninfo);
                if (extp_size < sizeof(*extp) + extra_size) {
                        need_more:
                        extp_size = sizeof(*extp) + extra_size;
                        goto again;
                }
        }
-               
        return extp;
  }
  
@@@ -339,7 -368,7 +368,7 @@@ struct mtd_info *cfi_cmdset_0001(struc
        mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
  
        if (cfi->cfi_mode == CFI_MODE_CFI) {
-               /* 
+               /*
                 * It's a real CFI chip, not one for which the probe
                 * routine faked a CFI structure. So we read the feature
                 * table from it.
                }
  
                /* Install our own private info structure */
-               cfi->cmdset_priv = extp;        
+               cfi->cmdset_priv = extp;
  
                cfi_fixup(mtd, cfi_fixup_table);
  
  #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
- #endif        
+ #endif
  
                if(extp->SuspendCmdSupport & 1) {
                        printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
                cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
                cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
                cfi->chips[i].ref_point_counter = 0;
-       }               
+       }
  
        map->fldrv = &cfi_intelext_chipdrv;
-       
        return cfi_intelext_setup(mtd);
  }
  
@@@ -399,13 -428,13 +428,13 @@@ static struct mtd_info *cfi_intelext_se
        mtd->size = devsize * cfi->numchips;
  
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                        * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) { 
+       if (!mtd->eraseregions) {
                printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
                goto setup_err;
        }
-       
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
                ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
        }
  
        for (i=0; i<mtd->numeraseregions;i++){
-               printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+               printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n",
                       i,mtd->eraseregions[i].offset,
                       mtd->eraseregions[i].erasesize,
                       mtd->eraseregions[i].numblocks);
  
   setup_err:
        if(mtd) {
 -              if(mtd->eraseregions)
 -                      kfree(mtd->eraseregions);
 +              kfree(mtd->eraseregions);
                kfree(mtd);
        }
        kfree(cfi->cmdset_priv);
@@@ -480,7 -510,7 +509,7 @@@ static int cfi_intelext_partition_fixup
         * arrangement at this point. This can be rearranged in the future
         * if someone feels motivated enough.  --nico
         */
-       if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3'
+       if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
            && extp->FeatureSupport & (1 << 9)) {
                struct cfi_private *newcfi;
                struct flchip *chip;
                       sizeof(struct cfi_intelext_otpinfo);
  
                /* Burst Read info */
-               offs += 6;
+               offs += extp->extra[offs+1]+2;
  
                /* Number of partition regions */
                numregions = extp->extra[offs];
                offs += 1;
  
+               /* skip the sizeof(partregion) field in CFI 1.4 */
+               if (extp->MinorVersion >= '4')
+                       offs += 2;
                /* Number of hardware partitions */
                numparts = 0;
                for (i = 0; i < numregions; i++) {
                                  sizeof(struct cfi_intelext_blockinfo);
                }
  
+               /* Programming Region info */
+               if (extp->MinorVersion >= '4') {
+                       struct cfi_intelext_programming_regioninfo *prinfo;
+                       prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
+                       MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift;
+                       MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
+                       MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
+                       mtd->flags |= MTD_PROGRAM_REGIONS;
+                       printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
+                              map->name, MTD_PROGREGION_SIZE(mtd),
+                              MTD_PROGREGION_CTRLMODE_VALID(mtd),
+                              MTD_PROGREGION_CTRLMODE_INVALID(mtd));
+               }
                /*
                 * All functions below currently rely on all chips having
                 * the same geometry so we'll just assume that all hardware
@@@ -653,8 -701,8 +700,8 @@@ static int get_chip(struct map_info *ma
                                break;
  
                        if (time_after(jiffies, timeo)) {
-                               printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n", 
-                                      status.x[0]);
+                               printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n",
+                                      map->name, status.x[0]);
                                return -EIO;
                        }
                        spin_unlock(chip->mutex);
                        /* Someone else might have been playing with it. */
                        goto retry;
                }
-                               
        case FL_READY:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
                                map_write(map, CMD(0x70), adr);
                                chip->state = FL_ERASING;
                                chip->oldstate = FL_READY;
-                               printk(KERN_ERR "Chip not ready after erase "
-                                      "suspended: status = 0x%lx\n", status.x[0]);
+                               printk(KERN_ERR "%s: Chip not ready after erase "
+                                      "suspended: status = 0x%lx\n", map->name, status.x[0]);
                                return -EIO;
                        }
  
@@@ -782,14 -830,14 +829,14 @@@ static void put_chip(struct map_info *m
        switch(chip->oldstate) {
        case FL_ERASING:
                chip->state = chip->oldstate;
-               /* What if one interleaved chip has finished and the 
+               /* What if one interleaved chip has finished and the
                   other hasn't? The old code would leave the finished
-                  one in READY mode. That's bad, and caused -EROFS 
+                  one in READY mode. That's bad, and caused -EROFS
                   errors to be returned from do_erase_oneblock because
                   that's the only bit it checked for at the time.
-                  As the state machine appears to explicitly allow 
+                  As the state machine appears to explicitly allow
                   sending the 0x70 (Read Status) command to an erasing
-                  chip and expecting it to be ignored, that's what we 
+                  chip and expecting it to be ignored, that's what we
                   do. */
                map_write(map, CMD(0xd0), adr);
                map_write(map, CMD(0x70), adr);
                DISABLE_VPP(map);
                break;
        default:
-               printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate);
+               printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
        }
        wake_up(&chip->wq);
  }
@@@ -1025,8 -1073,8 +1072,8 @@@ static int do_point_onechip (struct map
  
        adr += chip->start;
  
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
  
        spin_lock(chip->mutex);
  
@@@ -1054,7 -1102,7 +1101,7 @@@ static int cfi_intelext_point (struct m
  
        if (!map->virt || (from + len > mtd->size))
                return -EINVAL;
-       
        *mtdbuf = (void *)map->virt + from;
        *retlen = 0;
  
  
                *retlen += thislen;
                len -= thislen;
-               
                ofs = 0;
                chipnum++;
        }
@@@ -1120,7 -1168,7 +1167,7 @@@ static void cfi_intelext_unpoint (struc
                        if(chip->ref_point_counter == 0)
                                chip->state = FL_READY;
                } else
-                       printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
+                       printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */
  
                put_chip(map, chip, chip->start);
                spin_unlock(chip->mutex);
@@@ -1139,8 -1187,8 +1186,8 @@@ static inline int do_read_onechip(struc
  
        adr += chip->start;
  
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
  
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_addr, FL_READY);
@@@ -1195,7 -1243,7 +1242,7 @@@ static int cfi_intelext_read (struct mt
                *retlen += thislen;
                len -= thislen;
                buf += thislen;
-               
                ofs = 0;
                chipnum++;
        }
@@@ -1212,12 -1260,17 +1259,17 @@@ static int __xipram do_write_oneword(st
  
        adr += chip->start;
  
-       /* Let's determine this according to the interleave only once */
+       /* Let's determine those according to the interleave only once */
        status_OK = CMD(0x80);
        switch (mode) {
-       case FL_WRITING:   write_cmd = CMD(0x40); break;
-       case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
-       default: return -EINVAL;
+       case FL_WRITING:
+               write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
+               break;
+       case FL_OTP_WRITE:
+               write_cmd = CMD(0xc0);
+               break;
+       default:
+               return -EINVAL;
        }
  
        spin_lock(chip->mutex);
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
                        xip_enable(map, chip, adr);
-                       printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
+                       printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
                        ret = -EIO;
                        goto out;
                }
        if (!z) {
                chip->word_write_time--;
                if (!chip->word_write_time)
-                       chip->word_write_time++;
+                       chip->word_write_time = 1;
        }
-       if (z > 1) 
+       if (z > 1)
                chip->word_write_time++;
  
        /* Done and happy. */
        chip->state = FL_STATUS;
  
-       /* check for lock bit */
-       if (map_word_bitsset(map, status, CMD(0x02))) {
-               /* clear status */
+       /* check for errors */
+       if (map_word_bitsset(map, status, CMD(0x1a))) {
+               unsigned long chipstatus = MERGESTATUS(status);
+               /* reset status */
                map_write(map, CMD(0x50), adr);
-               /* put back into read status register mode */
                map_write(map, CMD(0x70), adr);
-               ret = -EROFS;
+               xip_enable(map, chip, adr);
+               if (chipstatus & 0x02) {
+                       ret = -EROFS;
+               } else if (chipstatus & 0x08) {
+                       printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name);
+                       ret = -EIO;
+               } else {
+                       printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus);
+                       ret = -EINVAL;
+               }
+               goto out;
        }
  
        xip_enable(map, chip, adr);
   out: put_chip(map, chip, adr);
        spin_unlock(chip->mutex);
        return ret;
  }
  
@@@ -1328,7 -1394,7 +1393,7 @@@ static int cfi_intelext_write_words (st
  
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                               bus_ofs, datum, FL_WRITING);
-               if (ret) 
+               if (ret)
                        return ret;
  
                len -= n;
                (*retlen) += n;
  
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
        }
-       
        while(len >= map_bankwidth(map)) {
                map_word datum = map_word_load(map, buf);
  
                len -= map_bankwidth(map);
  
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
  
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                       ofs, datum, FL_WRITING);
-               if (ret) 
+               if (ret)
                        return ret;
-               
                (*retlen) += len;
        }
  
  }
  
  
- static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, 
-                                   unsigned long adr, const u_char *buf, int len)
+ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
+                                   unsigned long adr, const struct kvec **pvec,
+                                   unsigned long *pvec_seek, int len)
  {
        struct cfi_private *cfi = map->fldrv_priv;
-       map_word status, status_OK;
+       map_word status, status_OK, write_cmd, datum;
        unsigned long cmd_adr, timeo;
-       int wbufsize, z, ret=0, bytes, words;
+       int wbufsize, z, ret=0, word_gap, words;
+       const struct kvec *vec;
+       unsigned long vec_seek;
  
        wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        adr += chip->start;
        cmd_adr = adr & ~(wbufsize-1);
-       
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
+       write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
  
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_adr, FL_WRITING);
        xip_disable(map, chip, cmd_adr);
  
        /* Â§4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
-          [...], the device will not accept any more Write to Buffer commands". 
+          [...], the device will not accept any more Write to Buffer commands".
           So we must check here and reset those bits if they're set. Otherwise
           we're just pissing in the wind */
        if (chip->state != FL_STATUS)
  
        z = 0;
        for (;;) {
-               map_write(map, CMD(0xe8), cmd_adr);
+               map_write(map, write_cmd, cmd_adr);
  
                status = map_read(map, cmd_adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        map_write(map, CMD(0x50), cmd_adr);
                        map_write(map, CMD(0x70), cmd_adr);
                        xip_enable(map, chip, cmd_adr);
-                       printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
-                              status.x[0], Xstatus.x[0]);
+                       printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
+                              map->name, status.x[0], Xstatus.x[0]);
                        ret = -EIO;
                        goto out;
                }
        }
  
+       /* Figure out the number of words to write */
+       word_gap = (-adr & (map_bankwidth(map)-1));
+       words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
+       if (!word_gap) {
+               words--;
+       } else {
+               word_gap = map_bankwidth(map) - word_gap;
+               adr -= word_gap;
+               datum = map_word_ff(map);
+       }
        /* Write length of data to come */
-       bytes = len & (map_bankwidth(map)-1);
-       words = len / map_bankwidth(map);
-       map_write(map, CMD(words - !bytes), cmd_adr );
+       map_write(map, CMD(words), cmd_adr );
  
        /* Write data */
-       z = 0;
-       while(z < words * map_bankwidth(map)) {
-               map_word datum = map_word_load(map, buf);
-               map_write(map, datum, adr+z);
+       vec = *pvec;
+       vec_seek = *pvec_seek;
+       do {
+               int n = map_bankwidth(map) - word_gap;
+               if (n > vec->iov_len - vec_seek)
+                       n = vec->iov_len - vec_seek;
+               if (n > len)
+                       n = len;
  
-               z += map_bankwidth(map);
-               buf += map_bankwidth(map);
-       }
+               if (!word_gap && len < map_bankwidth(map))
+                       datum = map_word_ff(map);
  
-       if (bytes) {
-               map_word datum;
+               datum = map_word_load_partial(map, datum,
+                                             vec->iov_base + vec_seek,
+                                             word_gap, n);
  
-               datum = map_word_ff(map);
-               datum = map_word_load_partial(map, datum, buf, 0, bytes);
-               map_write(map, datum, adr+z);
-       }
+               len -= n;
+               word_gap += n;
+               if (!len || word_gap == map_bankwidth(map)) {
+                       map_write(map, datum, adr);
+                       adr += map_bankwidth(map);
+                       word_gap = 0;
+               }
+               vec_seek += n;
+               if (vec_seek == vec->iov_len) {
+                       vec++;
+                       vec_seek = 0;
+               }
+       } while (len);
+       *pvec = vec;
+       *pvec_seek = vec_seek;
  
        /* GO GO GO */
        map_write(map, CMD(0xd0), cmd_adr);
        chip->state = FL_WRITING;
  
-       INVALIDATE_CACHE_UDELAY(map, chip, 
+       INVALIDATE_CACHE_UDELAY(map, chip,
                                cmd_adr, len,
                                chip->buffer_write_time);
  
  
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
+                       map_write(map, CMD(0x70), cmd_adr);
                        chip->state = FL_STATUS;
                        xip_enable(map, chip, cmd_adr);
-                       printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
+                       printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
                        ret = -EIO;
                        goto out;
                }
-               
                /* Latency issues. Drop the lock, wait a while and retry */
                z++;
                UDELAY(map, chip, cmd_adr, 1);
        if (!z) {
                chip->buffer_write_time--;
                if (!chip->buffer_write_time)
-                       chip->buffer_write_time++;
+                       chip->buffer_write_time = 1;
        }
-       if (z > 1) 
+       if (z > 1)
                chip->buffer_write_time++;
  
        /* Done and happy. */
        chip->state = FL_STATUS;
  
-       /* check for lock bit */
-       if (map_word_bitsset(map, status, CMD(0x02))) {
-               /* clear status */
+       /* check for errors */
+       if (map_word_bitsset(map, status, CMD(0x1a))) {
+               unsigned long chipstatus = MERGESTATUS(status);
+               /* reset status */
                map_write(map, CMD(0x50), cmd_adr);
-               /* put back into read status register mode */
-               map_write(map, CMD(0x70), adr);
-               ret = -EROFS;
+               map_write(map, CMD(0x70), cmd_adr);
+               xip_enable(map, chip, cmd_adr);
+               if (chipstatus & 0x02) {
+                       ret = -EROFS;
+               } else if (chipstatus & 0x08) {
+                       printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name);
+                       ret = -EIO;
+               } else {
+                       printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus);
+                       ret = -EINVAL;
+               }
+               goto out;
        }
  
        xip_enable(map, chip, cmd_adr);
        return ret;
  }
  
- static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 
-                                      size_t len, size_t *retlen, const u_char *buf)
+ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
+                               unsigned long count, loff_t to, size_t *retlen)
  {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        int ret = 0;
        int chipnum;
-       unsigned long ofs;
+       unsigned long ofs, vec_seek, i;
+       size_t len = 0;
+       for (i = 0; i < count; i++)
+               len += vecs[i].iov_len;
  
        *retlen = 0;
        if (!len)
                return 0;
  
        chipnum = to >> cfi->chipshift;
-       ofs = to  - (chipnum << cfi->chipshift);
-       /* If it's not bus-aligned, do the first word write */
-       if (ofs & (map_bankwidth(map)-1)) {
-               size_t local_len = (-ofs)&(map_bankwidth(map)-1);
-               if (local_len > len)
-                       local_len = len;
-               ret = cfi_intelext_write_words(mtd, to, local_len,
-                                              retlen, buf);
-               if (ret)
-                       return ret;
-               ofs += local_len;
-               buf += local_len;
-               len -= local_len;
-               if (ofs >> cfi->chipshift) {
-                       chipnum ++;
-                       ofs = 0;
-                       if (chipnum == cfi->numchips)
-                               return 0;
-               }
-       }
+       ofs = to - (chipnum << cfi->chipshift);
+       vec_seek = 0;
  
-       while(len) {
+       do {
                /* We must not cross write block boundaries */
                int size = wbufsize - (ofs & (wbufsize-1));
  
                if (size > len)
                        size = len;
-               ret = do_write_buffer(map, &cfi->chips[chipnum], 
-                                     ofs, buf, size);
+               ret = do_write_buffer(map, &cfi->chips[chipnum],
+                                     ofs, &vecs, &vec_seek, size);
                if (ret)
                        return ret;
  
                ofs += size;
-               buf += size;
                (*retlen) += size;
                len -= size;
  
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
-       }
+       } while (len);
        return 0;
  }
  
+ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
+                                      size_t len, size_t *retlen, const u_char *buf)
+ {
+       struct kvec vec;
+       vec.iov_base = (void *) buf;
+       vec.iov_len = len;
+       return cfi_intelext_writev(mtd, &vec, 1, to, retlen);
+ }
  static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
                                      unsigned long adr, int len, void *thunk)
  {
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, adr);
-                       /* Clear status bits */
-                       map_write(map, CMD(0x50), adr);
-                       map_write(map, CMD(0x70), adr);
                        xip_enable(map, chip, adr);
-                       printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n",
-                              adr, status.x[0], Xstatus.x[0]);
+                       printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
                        ret = -EIO;
                        goto out;
                }
-               
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1000000/HZ);
        }
        chip->state = FL_STATUS;
        status = map_read(map, adr);
  
-       /* check for lock bit */
+       /* check for errors */
        if (map_word_bitsset(map, status, CMD(0x3a))) {
-               unsigned long chipstatus;
+               unsigned long chipstatus = MERGESTATUS(status);
  
                /* Reset the error bits */
                map_write(map, CMD(0x50), adr);
                map_write(map, CMD(0x70), adr);
                xip_enable(map, chip, adr);
  
-               chipstatus = MERGESTATUS(status);
                if ((chipstatus & 0x30) == 0x30) {
-                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus);
-                       ret = -EIO;
+                       printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus);
+                       ret = -EINVAL;
                } else if (chipstatus & 0x02) {
                        /* Protection bit set */
                        ret = -EROFS;
                } else if (chipstatus & 0x8) {
                        /* Voltage */
-                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus);
+                       printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name);
                        ret = -EIO;
-               } else if (chipstatus & 0x20) {
-                       if (retries--) {
-                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
-                               timeo = jiffies + HZ;
-                               put_chip(map, chip, adr);
-                               spin_unlock(chip->mutex);
-                               goto retry;
-                       }
-                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus);
+               } else if (chipstatus & 0x20 && retries--) {
+                       printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
+                       timeo = jiffies + HZ;
+                       put_chip(map, chip, adr);
+                       spin_unlock(chip->mutex);
+                       goto retry;
+               } else {
+                       printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus);
                        ret = -EIO;
                }
-       } else {
-               xip_enable(map, chip, adr);
-               ret = 0;
+               goto out;
        }
  
+       xip_enable(map, chip, adr);
   out: put_chip(map, chip, adr);
        spin_unlock(chip->mutex);
        return ret;
@@@ -1754,7 -1849,7 +1848,7 @@@ int cfi_intelext_erase_varsize(struct m
  
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
        return 0;
  }
  
@@@ -1775,7 -1870,7 +1869,7 @@@ static void cfi_intelext_sync (struct m
                if (!ret) {
                        chip->oldstate = chip->state;
                        chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
                chip = &cfi->chips[i];
  
                spin_lock(chip->mutex);
-               
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        chip->oldstate = FL_READY;
@@@ -1846,7 -1941,7 +1940,7 @@@ static int __xipram do_xxlock_oneblock(
  
        ENABLE_VPP(map);
        xip_disable(map, chip, adr);
-       
        map_write(map, CMD(0x60), adr);
        if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
                map_write(map, CMD(0x01), adr);
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, adr);
                        xip_enable(map, chip, adr);
-                       printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n",
-                              status.x[0], Xstatus.x[0]);
+                       printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
                        put_chip(map, chip, adr);
                        spin_unlock(chip->mutex);
                        return -EIO;
                }
-               
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
        }
-       
        /* Done and happy. */
        chip->state = FL_STATUS;
        xip_enable(map, chip, adr);
@@@ -1912,9 -2004,9 +2003,9 @@@ static int cfi_intelext_lock(struct mtd
                ofs, len, 0);
  #endif
  
-       ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, 
+       ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
                ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
-       
  #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
@@@ -1938,20 -2030,20 +2029,20 @@@ static int cfi_intelext_unlock(struct m
  
        ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
                                        ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
-       
  #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
-       cfi_varsize_frob(mtd, do_printlockstatus_oneblock, 
+       cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, 0);
  #endif
-       
        return ret;
  }
  
  #ifdef CONFIG_MTD_OTP
  
- typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 
+ typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
                        u_long data_offset, u_char *buf, u_int size,
                        u_long prot_offset, u_int groupno, u_int groupsize);
  
@@@ -2002,7 -2094,7 +2093,7 @@@ do_otp_write(struct map_info *map, stru
  
                datum = map_word_load_partial(map, datum, buf, gap, n);
                ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
-               if (ret) 
+               if (ret)
                        return ret;
  
                offset += n;
@@@ -2195,7 -2287,7 +2286,7 @@@ static int cfi_intelext_lock_user_prot_
                                     NULL, do_otp_lock, 1);
  }
  
- static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, 
+ static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
                                           struct otp_info *buf, size_t len)
  {
        size_t retlen;
@@@ -2238,7 -2330,7 +2329,7 @@@ static int cfi_intelext_suspend(struct 
                        if (chip->oldstate == FL_READY) {
                                chip->oldstate = chip->state;
                                chip->state = FL_PM_SUSPENDED;
-                               /* No need to wake_up() on this state change - 
+                               /* No need to wake_up() on this state change -
                                 * as the whole point is that nobody can do anything
                                 * with the chip now anyway.
                                 */
        if (ret) {
                for (i--; i >=0; i--) {
                        chip = &cfi->chips[i];
-                       
                        spin_lock(chip->mutex);
-                       
                        if (chip->state == FL_PM_SUSPENDED) {
                                /* No need to force it into a known state here,
                                   because we're returning failure, and it didn't
                        }
                        spin_unlock(chip->mutex);
                }
-       } 
-       
+       }
        return ret;
  }
  
@@@ -2292,11 -2384,11 +2383,11 @@@ static void cfi_intelext_resume(struct 
        struct flchip *chip;
  
        for (i=0; i<cfi->numchips; i++) {
-       
                chip = &cfi->chips[i];
  
                spin_lock(chip->mutex);
-               
                /* Go to known state. Chip may have been power cycled */
                if (chip->state == FL_PM_SUSPENDED) {
                        map_write(map, CMD(0xFF), cfi->chips[i].start);
@@@ -2318,7 -2410,7 +2409,7 @@@ static int cfi_intelext_reset(struct mt
                struct flchip *chip = &cfi->chips[i];
  
                /* force the completion of any ongoing operation
-                  and switch to array mode so any bootloader in 
+                  and switch to array mode so any bootloader in
                   flash is accessible for soft reboot. */
                spin_lock(chip->mutex);
                ret = get_chip(map, chip, chip->start, FL_SYNCING);
@@@ -2355,20 -2447,23 +2446,23 @@@ static void cfi_intelext_destroy(struc
        kfree(mtd->eraseregions);
  }
  
- static char im_name_1[]="cfi_cmdset_0001";
- static char im_name_3[]="cfi_cmdset_0003";
+ static char im_name_0001[] = "cfi_cmdset_0001";
+ static char im_name_0003[] = "cfi_cmdset_0003";
+ static char im_name_0200[] = "cfi_cmdset_0200";
  
  static int __init cfi_intelext_init(void)
  {
-       inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001);
-       inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001);
+       inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001);
+       inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001);
+       inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001);
        return 0;
  }
  
  static void __exit cfi_intelext_exit(void)
  {
-       inter_module_unregister(im_name_1);
-       inter_module_unregister(im_name_3);
+       inter_module_unregister(im_name_0001);
+       inter_module_unregister(im_name_0003);
+       inter_module_unregister(im_name_0200);
  }
  
  module_init(cfi_intelext_init);
index 0e6475050da91b90c47a78c8d6532395c55c482d,88c5f5a34cb7f8a37628c344890c08a046660d19..aed10bd5c3c3869cb52732d764004753a30aa319
   *
   * 4_by_16 work by Carolyn J. Smith
   *
-  * XIP support hooks by Vitaly Wool (based on code for Intel flash 
+  * XIP support hooks by Vitaly Wool (based on code for Intel flash
   * by Nicolas Pitre)
-  * 
+  *
   * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
   *
   * This code is GPL
   *
-  * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $
+  * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $
   *
   */
  
@@@ -93,7 -93,7 +93,7 @@@ static void cfi_tell_features(struct cf
        };
  
        printk("  Silicon revision: %d\n", extp->SiliconRevision >> 1);
-       printk("  Address sensitive unlock: %s\n", 
+       printk("  Address sensitive unlock: %s\n",
               (extp->SiliconRevision & 1) ? "Not required" : "Required");
  
        if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
        else
                printk("  Page mode: %d word page\n", extp->PageMode << 2);
  
-       printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", 
+       printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
               extp->VppMin >> 4, extp->VppMin & 0xf);
-       printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", 
+       printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
               extp->VppMax >> 4, extp->VppMax & 0xf);
  
        if (extp->TopBottom < ARRAY_SIZE(top_bottom))
@@@ -177,7 -177,7 +177,7 @@@ static void fixup_use_erase_chip(struc
                ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
                mtd->erase = cfi_amdstd_erase_chip;
        }
-       
  }
  
  static struct cfi_fixup cfi_fixup_table[] = {
@@@ -239,7 -239,7 +239,7 @@@ struct mtd_info *cfi_cmdset_0002(struc
  
        if (cfi->cfi_mode==CFI_MODE_CFI){
                unsigned char bootloc;
-               /* 
+               /*
                 * It's a real CFI chip, not one for which the probe
                 * routine faked a CFI structure. So we read the feature
                 * table from it.
                        return NULL;
                }
  
+               if (extp->MajorVersion != '1' ||
+                   (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+                       printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "
+                              "version %c.%c.\n",  extp->MajorVersion,
+                              extp->MinorVersion);
+                       kfree(extp);
+                       kfree(mtd);
+                       return NULL;
+               }
                /* Install our own private info structure */
-               cfi->cmdset_priv = extp;        
+               cfi->cmdset_priv = extp;
  
                /* Apply cfi device specific fixups */
                cfi_fixup(mtd, cfi_fixup_table);
  #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
- #endif        
+ #endif
  
                bootloc = extp->TopBottom;
                if ((bootloc != 2) && (bootloc != 3)) {
  
                if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
                        printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
-                       
                        for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
                                int j = (cfi->cfiq->NumEraseRegions-1)-i;
                                __u32 swap;
-                               
                                swap = cfi->cfiq->EraseRegionInfo[i];
                                cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
                                cfi->cfiq->EraseRegionInfo[j] = swap;
                cfi->addr_unlock2 = 0x2aa;
                /* Modify the unlock address if we are in compatibility mode */
                if (    /* x16 in x8 mode */
-                       ((cfi->device_type == CFI_DEVICETYPE_X8) && 
+                       ((cfi->device_type == CFI_DEVICETYPE_X8) &&
                                (cfi->cfiq->InterfaceDesc == 2)) ||
                        /* x32 in x16 mode */
                        ((cfi->device_type == CFI_DEVICETYPE_X16) &&
-                               (cfi->cfiq->InterfaceDesc == 4))) 
+                               (cfi->cfiq->InterfaceDesc == 4)))
                {
                        cfi->addr_unlock1 = 0xaaa;
                        cfi->addr_unlock2 = 0x555;
                cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
                cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
                cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
-       }               
-       
+       }
        map->fldrv = &cfi_amdstd_chipdrv;
-       
        return cfi_amdstd_setup(mtd);
  }
  
@@@ -326,24 -336,24 +336,24 @@@ static struct mtd_info *cfi_amdstd_setu
        unsigned long offset = 0;
        int i,j;
  
-       printk(KERN_NOTICE "number of %s chips: %d\n", 
+       printk(KERN_NOTICE "number of %s chips: %d\n",
               (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
-       /* Select the correct geometry setup */ 
+       /* Select the correct geometry setup */
        mtd->size = devsize * cfi->numchips;
  
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                                    * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) { 
+       if (!mtd->eraseregions) {
                printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
                goto setup_err;
        }
-                       
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
                ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
                ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
-                       
                if (mtd->erasesize < ersize) {
                        mtd->erasesize = ersize;
                }
  
   setup_err:
        if(mtd) {
 -              if(mtd->eraseregions)
 -                      kfree(mtd->eraseregions);
 +              kfree(mtd->eraseregions);
                kfree(mtd);
        }
        kfree(cfi->cmdset_priv);
@@@ -429,7 -440,7 +439,7 @@@ static int __xipram chip_good(struct ma
        oldd = map_read(map, addr);
        curd = map_read(map, addr);
  
-       return  map_word_equal(map, oldd, curd) && 
+       return  map_word_equal(map, oldd, curd) &&
                map_word_equal(map, curd, expected);
  }
  
@@@ -461,7 -472,7 +471,7 @@@ static int get_chip(struct map_info *ma
                        /* Someone else might have been playing with it. */
                        goto retry;
                }
-                               
        case FL_READY:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
                                printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
                                return -EIO;
                        }
-                       
                        spin_unlock(chip->mutex);
                        cfi_udelay(1);
                        spin_lock(chip->mutex);
@@@ -607,7 -618,7 +617,7 @@@ static void __xipram xip_enable(struct 
   * When a delay is required for the flash operation to complete, the
   * xip_udelay() function is polling for both the given timeout and pending
   * (but still masked) hardware interrupts.  Whenever there is an interrupt
-  * pending then the flash erase operation is suspended, array mode restored 
+  * pending then the flash erase operation is suspended, array mode restored
   * and interrupts unmasked.  Task scheduling might also happen at that
   * point.  The CPU eventually returns from the interrupt or the call to
   * schedule() and the suspended flash operation is resumed for the remaining
@@@ -631,9 -642,9 +641,9 @@@ static void __xipram xip_udelay(struct 
                    ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
                    (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
                        /*
-                        * Let's suspend the erase operation when supported.  
-                        * Note that we currently don't try to suspend 
-                        * interleaved chips if there is already another 
+                        * Let's suspend the erase operation when supported.
+                        * Note that we currently don't try to suspend
+                        * interleaved chips if there is already another
                         * operation suspended (imagine what happens
                         * when one chip was already done with the current
                         * operation while another chip suspended it, then
@@@ -769,8 -780,8 +779,8 @@@ static inline int do_read_onechip(struc
  
        adr += chip->start;
  
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
  
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_addr, FL_READY);
@@@ -850,7 -861,7 +860,7 @@@ static inline int do_read_secsi_onechip
  #endif
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-               
                spin_unlock(chip->mutex);
  
                schedule();
                timeo = jiffies + HZ;
  
                goto retry;
-       }       
+       }
  
        adr += chip->start;
  
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-       
        map_copy_from(map, buf, adr, len);
  
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-       
        wake_up(&chip->wq);
        spin_unlock(chip->mutex);
  
@@@ -987,7 -998,7 +997,7 @@@ static int __xipram do_write_oneword(st
                                chip->word_write_time);
  
        /* See comment above for timeout value. */
-       timeo = jiffies + uWriteTimeout; 
+       timeo = jiffies + uWriteTimeout;
        for (;;) {
                if (chip->state != FL_WRITING) {
                        /* Someone's suspended the write. Sleep */
                        continue;
                }
  
-               if (chip_ready(map, adr))
-                       break;
-               if (time_after(jiffies, timeo)) {
+               if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
                        xip_enable(map, chip, adr);
                        printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
                        xip_disable(map, chip, adr);
-                         break;
+                       break;
                }
  
+               if (chip_ready(map, adr))
+                       break;
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
        }
                map_write( map, CMD(0xF0), chip->start );
                /* FIXME - should have reset delay before continuing */
  
-               if (++retry_cnt <= MAX_WORD_RETRIES) 
+               if (++retry_cnt <= MAX_WORD_RETRIES)
                        goto retry;
  
                ret = -EIO;
@@@ -1090,27 -1101,27 +1100,27 @@@ static int cfi_amdstd_write_words(struc
  
                /* Number of bytes to copy from buffer */
                n = min_t(int, len, map_bankwidth(map)-i);
-               
                tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
  
-               ret = do_write_oneword(map, &cfi->chips[chipnum], 
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
                                       bus_ofs, tmp_buf);
-               if (ret) 
+               if (ret)
                        return ret;
-               
                ofs += n;
                buf += n;
                (*retlen) += n;
                len -= n;
  
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
        }
-       
        /* We are now aligned, write as much as possible */
        while(len >= map_bankwidth(map)) {
                map_word datum;
                len -= map_bankwidth(map);
  
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                spin_unlock(cfi->chips[chipnum].mutex);
  
                tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
-       
-               ret = do_write_oneword(map, &cfi->chips[chipnum], 
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
                                ofs, tmp_buf);
-               if (ret) 
+               if (ret)
                        return ret;
-               
                (*retlen) += len;
        }
  
   * FIXME: interleaved mode not tested, and probably not supported!
   */
  static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
-                                   unsigned long adr, const u_char *buf, 
+                                   unsigned long adr, const u_char *buf,
                                    int len)
  {
        struct cfi_private *cfi = map->fldrv_priv;
        XIP_INVAL_CACHED_RANGE(map, adr, len);
        ENABLE_VPP(map);
        xip_disable(map, chip, cmd_adr);
-       
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
                                adr, map_bankwidth(map),
                                chip->word_write_time);
  
-       timeo = jiffies + uWriteTimeout; 
-               
+       timeo = jiffies + uWriteTimeout;
        for (;;) {
                if (chip->state != FL_WRITING) {
                        /* Someone's suspended the write. Sleep */
                        continue;
                }
  
+               if (time_after(jiffies, timeo) && !chip_ready(map, adr))
+                       break;
                if (chip_ready(map, adr)) {
                        xip_enable(map, chip, adr);
                        goto op_done;
                }
-                   
-               if( time_after(jiffies, timeo))
-                       break;
  
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
@@@ -1342,7 -1353,7 +1352,7 @@@ static int cfi_amdstd_write_buffers(str
                if (size % map_bankwidth(map))
                        size -= size % map_bankwidth(map);
  
-               ret = do_write_buffer(map, &cfi->chips[chipnum], 
+               ret = do_write_buffer(map, &cfi->chips[chipnum],
                                      ofs, buf, size);
                if (ret)
                        return ret;
                len -= size;
  
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
@@@ -1570,7 -1581,7 +1580,7 @@@ int cfi_amdstd_erase_varsize(struct mtd
  
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
        return 0;
  }
  
@@@ -1593,7 -1604,7 +1603,7 @@@ static int cfi_amdstd_erase_chip(struc
  
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
        return 0;
  }
  
@@@ -1620,7 -1631,7 +1630,7 @@@ static void cfi_amdstd_sync (struct mtd
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
                default:
                        /* Not an idle state */
                        add_wait_queue(&chip->wq, &wait);
-                       
                        spin_unlock(chip->mutex);
  
                        schedule();
  
                        remove_wait_queue(&chip->wq, &wait);
-                       
                        goto retry;
                }
        }
                chip = &cfi->chips[i];
  
                spin_lock(chip->mutex);
-               
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        wake_up(&chip->wq);
@@@ -1678,7 -1689,7 +1688,7 @@@ static int cfi_amdstd_suspend(struct mt
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_PM_SUSPENDED;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
                        chip = &cfi->chips[i];
  
                        spin_lock(chip->mutex);
-               
                        if (chip->state == FL_PM_SUSPENDED) {
                                chip->state = chip->oldstate;
                                wake_up(&chip->wq);
                        spin_unlock(chip->mutex);
                }
        }
-       
        return ret;
  }
  
@@@ -1720,11 -1731,11 +1730,11 @@@ static void cfi_amdstd_resume(struct mt
        struct flchip *chip;
  
        for (i=0; i<cfi->numchips; i++) {
-       
                chip = &cfi->chips[i];
  
                spin_lock(chip->mutex);
-               
                if (chip->state == FL_PM_SUSPENDED) {
                        chip->state = FL_READY;
                        map_write(map, CMD(0xF0), chip->start);
@@@ -1741,7 -1752,6 +1751,7 @@@ static void cfi_amdstd_destroy(struct m
  {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
 +
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
        kfree(cfi);
index 59a29e616a226f82112851ef76ae8a57ca1db012,ff585788880de417077b717f5aa52b14d3353e81..f9db52f6bf00f40156ece013ffd6f37e60769aee
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: blkmtd.c,v 1.24 2004/11/16 18:29:01 dwmw2 Exp $
+  * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $
   *
   * blkmtd.c - use a block device as a fake MTD
   *
@@@ -39,7 -39,7 +39,7 @@@
  
  /* Default erase size in K, always make it a multiple of PAGE_SIZE */
  #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)       /* 128KiB */
- #define VERSION "$Revision: 1.24 $"
+ #define VERSION "$Revision: 1.27 $"
  
  /* Info for the block device */
  struct blkmtd_dev {
@@@ -117,7 -117,7 +117,7 @@@ static int bi_write_complete(struct bi
                unlock_page(page);
                page_cache_release(page);
        } while (bvec >= bio->bi_io_vec);
-       
        complete((struct completion*)bio->bi_private);
        return 0;
  }
@@@ -135,7 -135,7 +135,7 @@@ static int blkmtd_readpage(struct blkmt
                unlock_page(page);
                return 0;
        }
-       
        ClearPageUptodate(page);
        ClearPageError(page);
  
@@@ -539,8 -539,11 +539,8 @@@ static void free_device(struct blkmtd_d
  {
        DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
        if(dev) {
 -              if(dev->mtd_info.eraseregions)
 -                      kfree(dev->mtd_info.eraseregions);
 -              if(dev->mtd_info.name)
 -                      kfree(dev->mtd_info.name);
 -
 +              kfree(dev->mtd_info.eraseregions);
 +              kfree(dev->mtd_info.name);
                if(dev->blkdev) {
                        invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
                        close_bdev_excl(dev->blkdev);
@@@ -707,7 -710,7 +707,7 @@@ static struct blkmtd_dev *add_device(ch
                     dev->mtd_info.erasesize >> 10,
                     readonly ? "(read-only)" : "");
        }
-       
        return dev;
  
   devinit_err:
diff --combined drivers/mtd/inftlcore.c
index 8db65bf029ea6db3ed59f30a568d5434e1b8c067,8db8618c18d28f8ec501fdfae4a2e247323e0976..8a544890173d3c857c953eb149c68b14b145ba90
@@@ -1,4 -1,4 +1,4 @@@
- /* 
+ /*
   * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
   *
   * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
@@@ -7,7 -7,7 +7,7 @@@
   * (c) 1999 Machine Vision Holdings, Inc.
   * Author: David Woodhouse <dwmw2@infradead.org>
   *
-  * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $
+  * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $
   *
   * 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
@@@ -113,21 -113,23 +113,21 @@@ static void inftl_add_mtd(struct mtd_bl
  
        if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
                /*
-                 Oh no we don't have 
+                 Oh no we don't have
                   mbd.size == heads * cylinders * sectors
                */
                printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
                       "match size of 0x%lx.\n", inftl->mbd.size);
                printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
                        "(== 0x%lx sects)\n",
-                       inftl->cylinders, inftl->heads , inftl->sectors, 
+                       inftl->cylinders, inftl->heads , inftl->sectors,
                        (long)inftl->cylinders * (long)inftl->heads *
                        (long)inftl->sectors );
        }
  
        if (add_mtd_blktrans_dev(&inftl->mbd)) {
 -              if (inftl->PUtable)
 -                      kfree(inftl->PUtable);
 -              if (inftl->VUtable)
 -                      kfree(inftl->VUtable);
 +              kfree(inftl->PUtable);
 +              kfree(inftl->VUtable);
                kfree(inftl);
                return;
        }
@@@ -145,8 -147,10 +145,8 @@@ static void inftl_remove_dev(struct mtd
  
        del_mtd_blktrans_dev(dev);
  
 -      if (inftl->PUtable)
 -              kfree(inftl->PUtable);
 -      if (inftl->VUtable)
 -              kfree(inftl->VUtable);
 +      kfree(inftl->PUtable);
 +      kfree(inftl->VUtable);
        kfree(inftl);
  }
  
@@@ -219,7 -223,7 +219,7 @@@ static u16 INFTL_foldchain(struct INFTL
                       "Virtual Unit Chain %d!\n", thisVUC);
                return BLOCK_NIL;
        }
-       
        /*
         * Scan to find the Erase Unit which holds the actual data for each
         * 512-byte block within the Chain.
                                "Unit Chain 0x%x\n", thisVUC);
                        return BLOCK_NIL;
                }
-               
                thisEUN = inftl->PUtable[thisEUN];
        }
  
                 */
                  if (BlockMap[block] == BLOCK_NIL)
                          continue;
-                 
                  ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                        BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
-                       &retlen, movebuf); 
+                       &retlen, movebuf);
                  if (ret < 0) {
                        ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                                BlockMap[block]) + (block * SECTORSIZE),
                                SECTORSIZE, &retlen, movebuf);
-                       if (ret != -EIO) 
+                       if (ret != -EIO)
                                DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
                                        "away on retry?\n");
                  }
  static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
  {
        /*
-        * This is the part that needs some cleverness applied. 
+        * This is the part that needs some cleverness applied.
         * For now, I'm doing the minimum applicable to actually
         * get the thing to work.
         * Wear-levelling and other clever stuff needs to be implemented
@@@ -410,7 -414,7 +410,7 @@@ static int nrbits(unsigned int val, in
  }
  
  /*
-  * INFTL_findwriteunit: Return the unit number into which we can write 
+  * INFTL_findwriteunit: Return the unit number into which we can write
   *                      for this block. Make it available if it isn't already.
   */
  static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
                                 * Invalid block. Don't use it any more.
                                 * Must implement.
                                 */
-                               break;                  
+                               break;
                        }
-                       
-                       if (!silly--) { 
+                       if (!silly--) {
                                printk(KERN_WARNING "INFTL: infinite loop in "
                                        "Virtual Unit Chain 0x%x\n", thisVUC);
                                return 0xffff;
@@@ -478,7 -482,7 +478,7 @@@ hitused
  
  
                /*
-                * OK. We didn't find one in the existing chain, or there 
+                * OK. We didn't find one in the existing chain, or there
                 * is no existing chain. Allocate a new one.
                 */
                writeEUN = INFTL_findfreeblock(inftl, 0);
                        if (writeEUN == BLOCK_NIL) {
                                /*
                                 * Ouch. This should never happen - we should
-                                * always be able to make some room somehow. 
-                                * If we get here, we've allocated more storage 
+                                * always be able to make some room somehow.
+                                * If we get here, we've allocated more storage
                                 * space than actual media, or our makefreeblock
                                 * routine is missing something.
                                 */
                                INFTL_dumpVUchains(inftl);
  #endif
                                return BLOCK_NIL;
-                       }                       
+                       }
                }
  
                /*
                parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
                parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
                parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
-  
                oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
                oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
                oob.u.a.ANAC = anac;
                oob.u.b.parityPerField = parity;
                oob.u.b.discarded = 0xaa;
  
-               MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 
+               MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
                        SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
  
                inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
@@@ -598,7 -602,7 +598,7 @@@ static void INFTL_trydeletechain(struc
                       "Virtual Unit Chain %d!\n", thisVUC);
                return;
        }
-       
        /*
         * Scan through the Erase Units to determine whether any data is in
         * each of the 512-byte blocks within the Chain.
                                "Unit Chain 0x%x\n", thisVUC);
                        return;
                }
-               
                thisEUN = inftl->PUtable[thisEUN];
        }
  
@@@ -754,7 -758,7 +754,7 @@@ foundit
        return 0;
  }
  
- static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 
+ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                            char *buffer)
  {
        struct INFTLrecord *inftl = (void *)mbd;
@@@ -889,7 -893,7 +889,7 @@@ extern char inftlmountrev[]
  
  static int __init init_inftl(void)
  {
-       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, "
+       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
                "inftlmount.c %s\n", inftlmountrev);
  
        return register_mtd_blktrans(&inftl_tr);
diff --combined drivers/mtd/inftlmount.c
index 3dac53feeee27561a28b8cc6c35a1bd313ebb17a,b26aea1f640a8836f148451e366714f8db9fcd25..43fdc943388241bcceeacd66b410ec15612699d2
@@@ -1,14 -1,14 +1,14 @@@
- /* 
+ /*
   * inftlmount.c -- INFTL mount code with extensive checks.
   *
   * Author: Greg Ungerer (gerg@snapgear.com)
   * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
   *
   * Based heavily on the nftlmount.c code which is:
-  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+  * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
   * Copyright (C) 2000 Netgem S.A.
   *
-  * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $
+  * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 gleixner Exp $
   *
   * 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
@@@ -41,7 -41,7 +41,7 @@@
  #include <linux/mtd/inftl.h>
  #include <linux/mtd/compatmac.h>
  
- char inftlmountrev[]="$Revision: 1.16 $";
+ char inftlmountrev[]="$Revision: 1.18 $";
  
  /*
   * find_boot_record: Find the INFTL Media Header and its Spare copy which
@@@ -273,7 -273,7 +273,7 @@@ static int find_boot_record(struct INFT
                                inftl->nb_boot_blocks);
                        return -1;
                }
-               
                inftl->mbd.size  = inftl->numvunits *
                        (inftl->EraseSize / SECTORSIZE);
  
                                inftl->nb_blocks * sizeof(u16));
                        return -ENOMEM;
                }
-               
                /* Mark the blocks before INFTL MediaHeader as reserved */
                for (i = 0; i < inftl->nb_boot_blocks; i++)
                        inftl->PUtable[i] = BLOCK_RESERVED;
@@@ -380,7 -380,7 +380,7 @@@ static int check_free_sectors(struct IN
   *
   * Return: 0 when succeed, -1 on error.
   *
-  * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
+  * ToDo: 1. Is it neceressary to check_free_sector after erasing ??
   */
  int INFTL_formatblock(struct INFTLrecord *inftl, int block)
  {
@@@ -563,7 -563,7 +563,7 @@@ int INFTL_mount(struct INFTLrecord *s
        /* Search for INFTL MediaHeader and Spare INFTL Media Header */
        if (find_boot_record(s) < 0) {
                printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
-               return -1;
+               return -ENXIO;
        }
  
        /* Init the logical to physical table */
        /* Temporary buffer to store ANAC numbers. */
        ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
        if (!ANACtable) {
 -              printk(KERN_ERR "INFTL: Out of memory.\n");
 +              printk(KERN_WARNING "INFTL: allocation of ANACtable "
 +                              "failed (%zd bytes)\n",
 +                              s->nb_blocks * sizeof(u8));
                return -ENOMEM;
        }
 -
        memset(ANACtable, 0, s->nb_blocks);
  
        /*
  
                for (chain_length = 0; ; chain_length++) {
  
-                       if ((chain_length == 0) && 
+                       if ((chain_length == 0) &&
                            (s->PUtable[block] != BLOCK_NOTEXPLORED)) {
                                /* Nothing to do here, onto next block */
                                break;
                                        "in virtual chain %d\n",
                                        s->PUtable[block], logical_block);
                                s->PUtable[block] = BLOCK_NIL;
-                                       
                        }
                        if (ANACtable[block] != ANAC) {
                                /*
index 9a64149f431d2a547383bd97b1861e81fafd2596,60ca3be5406da9b976be18e5bb53fe89f40351b5..c350878d4592978ffece3fe1b1e97cb4caae5187
@@@ -2,7 -2,7 +2,7 @@@
   * amd76xrom.c
   *
   * Normal mappings of chips in physical memory
-  * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $
+  * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $
   */
  
  #include <linux/module.h>
@@@ -70,7 -70,7 +70,7 @@@ static void amd76xrom_cleanup(struct am
                list_del(&map->list);
                kfree(map);
        }
-       if (window->rsrc.parent) 
+       if (window->rsrc.parent)
                release_resource(&window->rsrc);
  
        if (window->virt) {
@@@ -107,7 -107,7 +107,7 @@@ static int __devinit amd76xrom_init_on
                window->phys = 0xffff0000; /* 64KiB */
        }
        window->size = 0xffffffffUL - window->phys + 1UL;
-       
        /*
         * Try to reserve the window mem region.  If this fails then
         * it is likely due to a fragment of the window being
        /* Enable writes through the rom window */
        pci_read_config_byte(pdev, 0x40, &byte);
        pci_write_config_byte(pdev, 0x40, byte | 1);
-       
        /* FIXME handle registers 0x80 - 0x8C the bios region locks */
  
        /* For write accesses caches are useless */
                        MOD_NAME, map->map.phys);
  
                /* There is no generic VPP support */
-               for(map->map.bankwidth = 32; map->map.bankwidth; 
+               for(map->map.bankwidth = 32; map->map.bankwidth;
                        map->map.bankwidth >>= 1)
                {
                        char **probe_type;
                for(i = 0; i < cfi->numchips; i++) {
                        cfi->chips[i].start += offset;
                }
-               
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
                if (add_mtd_device(map->mtd)) {
  
   out:
        /* Free any left over map structures */
 -      if (map) {
 -              kfree(map);
 -      }
 +      kfree(map);
        /* See if I have any map structures */
        if (list_empty(&window->maps)) {
                amd76xrom_cleanup(window);
@@@ -277,9 -279,9 +277,9 @@@ static void __devexit amd76xrom_remove_
  }
  
  static struct pci_device_id amd76xrom_pci_tbl[] = {
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
+       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,
                PCI_ANY_ID, PCI_ANY_ID, },
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
+       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
        { 0, }
index 8c19d722ac796178c9d0cda7ecd3de29c8223927,610dfcaa2c8635542bcc3d77372fb2d8704710d2..b7858eb935347acb767d2961de8896027b4b1674
@@@ -9,7 -9,7 +9,7 @@@
   *    20-Sep-2004  BJD  Initial version
   *    17-Jan-2005  BJD  Add whole device if no partitions found
   *
-  * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
+  * $Id: bast-flash.c,v 1.5 2005/11/07 11:14:26 gleixner Exp $
   *
   * 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
@@@ -75,7 -75,7 +75,7 @@@ static void bast_flash_setrw(int to
  
        local_irq_save(flags);
        val = __raw_readb(BAST_VA_CTRL3);
-       
        if (to)
                val |= BAST_CPLD_CTRL3_ROMWEN;
        else
@@@ -93,7 -93,7 +93,7 @@@ static int bast_flash_remove(struct dev
  
        dev_set_drvdata(dev, NULL);
  
-       if (info == NULL) 
+       if (info == NULL)
                return 0;
  
        if (info->map.virt != NULL)
                map_destroy(info->mtd);
        }
  
 -      if (info->partitions)
 -              kfree(info->partitions);
 +      kfree(info->partitions);
  
        if (info->area) {
                release_resource(info->area);
                kfree(info->area);
        }
-       
        kfree(info);
  
        return 0;
@@@ -137,15 -138,15 +137,15 @@@ static int bast_flash_probe(struct devi
  
        info->map.phys = res->start;
        info->map.size = res->end - res->start + 1;
-       info->map.name = dev->bus_id;   
+       info->map.name = dev->bus_id;
        info->map.bankwidth = 2;
-       
        if (info->map.size > AREA_MAXSIZE)
                info->map.size = AREA_MAXSIZE;
  
        pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__,
                 info->map.phys, info->map.size);
-       
        info->area = request_mem_region(res->start, info->map.size,
                                        pdev->name);
        if (info->area == NULL) {
                err = -EIO;
                goto exit_error;
        }
-  
        simple_map_init(&info->map);
  
        /* enable the write to the flash area */
        err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
        if (err > 0) {
                err = add_mtd_partitions(info->mtd, info->partitions, err);
-               if (err) 
+               if (err)
                        printk(KERN_ERR PFX "cannot add/parse partitions\n");
        } else {
                err = add_mtd_device(info->mtd);
  
  static struct device_driver bast_flash_driver = {
        .name           = "bast-nor",
+       .owner          = THIS_MODULE,
        .bus            = &platform_bus_type,
        .probe          = bast_flash_probe,
        .remove         = bast_flash_remove,
index c5e2111ba146df5535e0b90f451cc5c55d99ac63,aa9720ec4cd5e5f71cf4ed1fd6746524392af6c7..ea5073781b3a38265053e2710606d5ef26464854
@@@ -2,7 -2,7 +2,7 @@@
   * ichxrom.c
   *
   * Normal mappings of chips in physical memory
-  * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $
+  * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $
   */
  
  #include <linux/module.h>
@@@ -101,7 -101,7 +101,7 @@@ static int __devinit ichxrom_init_one (
         * you can only really attach a FWH to an ICHX there
         * a number of simplifications you can make.
         *
-        * Also you can page firmware hubs if an 8MB window isn't enough 
+        * Also you can page firmware hubs if an 8MB window isn't enough
         * but don't currently handle that case either.
         */
        window->pdev = pdev;
                window->phys = 0xfff00000;
        }
        else if ((byte & 0x80) == 0x80) {
-               window->phys = 0xfff80000; 
+               window->phys = 0xfff80000;
        }
  
        if (window->phys == 0) {
                 * in a factory setting.  So in-place programming
                 * needs to use a different method.
                 */
-               for(map->map.bankwidth = 32; map->map.bankwidth; 
+               for(map->map.bankwidth = 32; map->map.bankwidth;
                        map->map.bankwidth >>= 1)
                {
                        char **probe_type;
                for(i = 0; i < cfi->numchips; i++) {
                        cfi->chips[i].start += offset;
                }
-               
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
                if (add_mtd_device(map->mtd)) {
  
   out:
        /* Free any left over map structures */
 -      if (map) {
 -              kfree(map);
 -      }
 +      kfree(map);
 +
        /* See if I have any map structures */
        if (list_empty(&window->maps)) {
                ichxrom_cleanup(window);
@@@ -324,11 -325,11 +324,11 @@@ static void __devexit ichxrom_remove_on
  }
  
  static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, 
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
          PCI_ANY_ID, PCI_ANY_ID, },
index 93f50d6d5488817cd4d2af10072a7acddd6a12a2,549614693ac8e87e2999eeb5b242ba7adf8ac51e..fe738fd8d6f89f068910a82cd636a4bb431eb4c9
@@@ -1,28 -1,28 +1,28 @@@
  /*======================================================================
  
      drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver
-   
      Copyright (C) 2000 ARM Limited
      Copyright (C) 2003 Deep Blue Solutions Ltd.
-   
     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 of the License, or
     (at your option) any later version.
-   
     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
-   
-    This is access code for flashes using ARM's flash partitioning 
+    This is access code for flashes using ARM's flash partitioning
     standards.
  
-    $Id: integrator-flash.c,v 1.18 2004/11/01 13:26:15 rmk Exp $
+    $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $
  
  ======================================================================*/
  
@@@ -148,7 -148,8 +148,7 @@@ static int armflash_probe(struct devic
                        del_mtd_partitions(info->mtd);
                        map_destroy(info->mtd);
                }
 -              if (info->parts)
 -                      kfree(info->parts);
 +              kfree(info->parts);
  
   no_device:
                iounmap(base);
@@@ -175,7 -176,8 +175,7 @@@ static int armflash_remove(struct devic
                        del_mtd_partitions(info->mtd);
                        map_destroy(info->mtd);
                }
 -              if (info->parts)
 -                      kfree(info->parts);
 +              kfree(info->parts);
  
                iounmap(info->map.virt);
                release_resource(info->res);
index 70b0e0b82c34f8e7384b2fb0bae3ea51503dc10d,fbace127df30b2207d30defee6c6aa1ef1cf93d4..35097c9bbf50c5bb560fe5fce3b039a3a4c4eba3
@@@ -1,11 -1,11 +1,11 @@@
  /*
   * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
-  * 
+  *
   * (C) 2000 Nicolas Pitre <nico@cam.org>
   * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
   * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
-  * 
-  * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $
+  *
+  * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $
   */
  
  #include <linux/config.h>
@@@ -107,7 -107,7 +107,7 @@@ static struct mtd_partition h3xxx_parti
  #ifndef CONFIG_LAB
                mask_flags:     MTD_WRITEABLE,  /* force read-only */
  #endif
-       }, 
+       },
        {
                name:           "H3XXX root jffs2",
  #ifndef CONFIG_LAB
@@@ -148,7 -148,7 +148,7 @@@ static DEFINE_SPINLOCK(ipaq_vpp_lock)
  static void h3xxx_set_vpp(struct map_info *map, int vpp)
  {
        static int nest = 0;
-       
        spin_lock(&ipaq_vpp_lock);
        if (vpp)
                nest++;
@@@ -191,7 -191,7 +191,7 @@@ static unsigned long cs_phys[] = 
        SA1100_CS3_PHYS,
        SA1100_CS4_PHYS,
        SA1100_CS5_PHYS,
- #else 
+ #else
        PXA_CS0_PHYS,
        PXA_CS1_PHYS,
        PXA_CS2_PHYS,
@@@ -216,7 -216,7 +216,7 @@@ int __init ipaq_mtd_init(void
  
        /* Default flash bankwidth */
        // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
-       
        if (machine_is_h1900())
        {
                /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */
        else
                for(i=0; i<MAX_IPAQ_CS; i++)
                        ipaq_map[i].bankwidth = 4;
-                       
        /*
         * Static partition definition selection
         */
                                        return -ENXIO;
                        } else
                                printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);
-                       
                        /* do we really need this debugging? --joshua 20030703 */
                        // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);
                        my_sub_mtd[i]->owner = THIS_MODULE;
  #else
                mymtd = my_sub_mtd[0];
  
-               /* 
+               /*
                 *In the very near future, command line partition parsing
                 * will use the device name as 'mtd-id' instead of a value
                 * passed to the parse_cmdline_partitions() routine. Since
-                * the bootldr says 'ipaq', make sure it continues to work. 
+                * the bootldr says 'ipaq', make sure it continues to work.
                 */
                mymtd->name = "ipaq";
  
         */
  
         i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);
-                       
         if (i > 0) {
                 nb_parts = parsed_nr_parts = i;
                 parts = parsed_parts;
@@@ -423,15 -423,16 +423,15 @@@ static void __exit ipaq_mtd_cleanup(voi
  #endif
                map_destroy(mymtd);
  #ifdef CONFIG_MTD_CONCAT
-               for(i=0; i<MAX_IPAQ_CS; i++) 
+               for(i=0; i<MAX_IPAQ_CS; i++)
  #else
-                       for(i=1; i<MAX_IPAQ_CS; i++) 
- #endif                  
+                       for(i=1; i<MAX_IPAQ_CS; i++)
+ #endif
                        {
                                if (my_sub_mtd[i])
                                        map_destroy(my_sub_mtd[i]);
                        }
 -              if (parsed_parts)
 -                      kfree(parsed_parts);
 +              kfree(parsed_parts);
        }
  }
  
@@@ -444,14 -445,14 +444,14 @@@ static int __init h1900_special_case(vo
        ipaq_map[0].phys = 0x0;
        ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1);
        ipaq_map[0].bankwidth = 2;
-       
        printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
        mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);
        if (!mymtd)
                return -ENODEV;
        add_mtd_device(mymtd);
        printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");
-       
        return 0;
  }
  
index 2e7577492a2c3602b135386f0ac0f4b6d122214d,5b2fd3617c50f833437d0debcc1eafdc0eefc909..62d9e87d84e2863edc3690075d717d86b998ace8
@@@ -1,11 -1,11 +1,11 @@@
  /*
-  * $Id: iq80310.c,v 1.20 2004/11/04 13:24:15 gleixner Exp $
+  * $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
   *
   * Mapping for the Intel XScale IQ80310 evaluation board
   *
   * Author:    Nicolas Pitre
   * Copyright: (C) 2001 MontaVista Software Inc.
-  * 
+  *
   * 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.
@@@ -103,7 -103,8 +103,7 @@@ static void __exit cleanup_iq80310(void
        if (mymtd) {
                del_mtd_partitions(mymtd);
                map_destroy(mymtd);
 -              if (parsed_parts)
 -                      kfree(parsed_parts);
 +              kfree(parsed_parts);
        }
        if (iq80310_map.virt)
                iounmap((void *)iq80310_map.virt);
index 6f36497022d19bed60f57e78bd8882bf21b7dedb,aa29a4a741bf7ac2d1a6b24b947743db89c7f8d6..641eb2b55e9f4733b6cbc1d8ad8ef8e21e05b962
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $
+  * $Id: ixp2000.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $
   *
   * drivers/mtd/maps/ixp2000.c
   *
@@@ -14,7 -14,7 +14,7 @@@
   * 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.
-  * 
+  *
   */
  
  #include <linux/module.h>
@@@ -46,8 -46,8 +46,8 @@@ struct ixp2000_flash_info 
  };
  
  static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
- {     
-       unsigned long (*set_bank)(unsigned long) = 
+ {
+       unsigned long (*set_bank)(unsigned long) =
                (unsigned long(*)(unsigned long))map->map_priv_2;
  
        return (set_bank ? set_bank(ofs) : ofs);
@@@ -55,8 -55,8 +55,8 @@@
  
  #ifdef __ARMEB__
  /*
-  * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which 
-  * causes the lower address bits to be XORed with 0x11 on 8 bit accesses 
+  * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which
+  * causes the lower address bits to be XORed with 0x11 on 8 bit accesses
   * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44.
   */
  static int erratum44_workaround = 0;
@@@ -90,7 -90,7 +90,7 @@@ static void ixp2000_flash_copy_from(str
                              unsigned long from, ssize_t len)
  {
        from = flash_bank_setup(map, from);
-       while(len--) 
+       while(len--)
                *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
  }
  
@@@ -129,7 -129,8 +129,7 @@@ static int ixp2000_flash_remove(struct 
        if (info->map.map_priv_1)
                iounmap((void *) info->map.map_priv_1);
  
 -      if (info->partitions) {
 -              kfree(info->partitions); }
 +      kfree(info->partitions);
  
        if (info->res) {
                release_resource(info->res);
@@@ -148,11 -149,11 +148,11 @@@ static int ixp2000_flash_probe(struct d
        static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
        struct platform_device *dev = to_platform_device(_dev);
        struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
-       struct flash_platform_data *plat; 
+       struct flash_platform_data *plat;
        struct ixp2000_flash_info *info;
        unsigned long window_size;
        int err = -1;
-       
        if (!ixp_data)
                return -ENODEV;
  
                return -ENODEV;
  
        window_size = dev->resource->end - dev->resource->start + 1;
-       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", 
+       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n",
                        ixp_data->nr_banks, ((u32)window_size >> 20));
  
        if (plat->width != 1) {
        if(!info) {
                err = -ENOMEM;
                goto Error;
-       }       
+       }
        memzero(info, sizeof(struct ixp2000_flash_info));
  
        dev_set_drvdata(&dev->dev, info);
         * not attempt to do a direct access on us.
         */
        info->map.phys = NO_XIP;
-       
        info->nr_banks = ixp_data->nr_banks;
        info->map.size = ixp_data->nr_banks * window_size;
        info->map.bankwidth = 1;
        /*
         * map_priv_2 is used to store a ptr to to the bank_setup routine
         */
-       info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup;
+       info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup;
  
        info->map.name = dev->dev.bus_id;
        info->map.read = ixp2000_flash_read8;
        info->map.copy_from = ixp2000_flash_copy_from;
        info->map.copy_to = ixp2000_flash_copy_to;
  
-       info->res = request_mem_region(dev->resource->start, 
-                       dev->resource->end - dev->resource->start + 1, 
+       info->res = request_mem_region(dev->resource->start,
+                       dev->resource->end - dev->resource->start + 1,
                        dev->dev.bus_id);
        if (!info->res) {
                dev_err(_dev, "Could not reserve memory region\n");
                goto Error;
        }
  
-       info->map.map_priv_1 = ioremap(dev->resource->start, 
+       info->map.map_priv_1 = (unsigned long) ioremap(dev->resource->start,
                                dev->resource->end - dev->resource->start + 1);
        if (!info->map.map_priv_1) {
                dev_err(_dev, "Failed to ioremap flash region\n");
index 0d87c02dee046f32070427b8e743ac550fa1f8ed,471553a3da69fa6f25edbf688fe9075b1addec1a..56b3a355bf7b83f934a77eeca368b2cdfa25d96c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $
+  * $Id: ixp4xx.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $
   *
   * drivers/mtd/maps/ixp4xx.c
   *
@@@ -45,7 -45,7 +45,7 @@@
  static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
  {
        map_word val;
-       val.x[0] = *(__u16 *) (map->map_priv_1 + ofs);
+       val.x[0] = le16_to_cpu(readw(map->virt + ofs));
        return val;
  }
  
@@@ -59,35 -59,35 +59,35 @@@ static void ixp4xx_copy_from(struct map
  {
        int i;
        u8 *dest = (u8 *) to;
-       u16 *src = (u16 *) (map->map_priv_1 + from);
+       void __iomem *src = map->virt + from;
        u16 data;
  
        for (i = 0; i < (len / 2); i++) {
-               data = src[i];
+               data = le16_to_cpu(readw(src + 2*i));
                dest[i * 2] = BYTE0(data);
                dest[i * 2 + 1] = BYTE1(data);
        }
  
        if (len & 1)
-               dest[len - 1] = BYTE0(src[i]);
+               dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i)));
  }
  
- /* 
+ /*
   * Unaligned writes are ignored, causing the 8-bit
   * probe to fail and proceed to the 16-bit probe (which succeeds).
   */
  static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
  {
        if (!(adr & 1))
-              *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
+               writew(cpu_to_le16(d.x[0]), map->virt + adr);
  }
  
- /* 
+ /*
   * Fast write16 function without the probing check above
   */
  static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
  {
-        *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
+       writew(cpu_to_le16(d.x[0]), map->virt + adr);
  }
  
  struct ixp4xx_flash_info {
@@@ -104,27 -104,21 +104,20 @@@ static int ixp4xx_flash_remove(struct d
        struct platform_device *dev = to_platform_device(_dev);
        struct flash_platform_data *plat = dev->dev.platform_data;
        struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev);
-       map_word d;
  
        dev_set_drvdata(&dev->dev, NULL);
  
        if(!info)
                return 0;
  
-       /*
-        * This is required for a soft reboot to work.
-        */
-       d.x[0] = 0xff;
-       ixp4xx_write16(&info->map, d, 0x55 * 0x2);
        if (info->mtd) {
                del_mtd_partitions(info->mtd);
                map_destroy(info->mtd);
        }
-       if (info->map.map_priv_1)
-               iounmap((void *) info->map.map_priv_1);
+       if (info->map.virt)
+               iounmap(info->map.virt);
  
 -      if (info->partitions)
 -              kfree(info->partitions);
 +      kfree(info->partitions);
  
        if (info->res) {
                release_resource(info->res);
        if (plat->exit)
                plat->exit();
  
-       /* Disable flash write */
-       *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE;
        return 0;
  }
  
@@@ -160,17 -151,11 +150,11 @@@ static int ixp4xx_flash_probe(struct de
        if(!info) {
                err = -ENOMEM;
                goto Error;
-       }       
+       }
        memzero(info, sizeof(struct ixp4xx_flash_info));
  
        dev_set_drvdata(&dev->dev, info);
  
-       /* 
-        * Enable flash write 
-        * TODO: Move this out to board specific code
-        */
-       *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
        /*
         * Tell the MTD layer we're not 1:1 mapped so that it does
         * not attempt to do a direct access on us.
        info->map.write = ixp4xx_probe_write16,
        info->map.copy_from = ixp4xx_copy_from,
  
-       info->res = request_mem_region(dev->resource->start, 
-                       dev->resource->end - dev->resource->start + 1, 
+       info->res = request_mem_region(dev->resource->start,
+                       dev->resource->end - dev->resource->start + 1,
                        "IXP4XXFlash");
        if (!info->res) {
                printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
                goto Error;
        }
  
-       info->map.map_priv_1 = ioremap(dev->resource->start,
-                           dev->resource->end - dev->resource->start + 1);
-       if (!info->map.map_priv_1) {
+       info->map.virt = ioremap(dev->resource->start,
+                                dev->resource->end - dev->resource->start + 1);
+       if (!info->map.virt) {
                printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
                err = -EIO;
                goto Error;
                goto Error;
        }
        info->mtd->owner = THIS_MODULE;
-       
        /* Use the fast version */
        info->map.write = ixp4xx_write16,
  
@@@ -258,4 -243,3 +242,3 @@@ module_exit(ixp4xx_flash_exit)
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems");
  MODULE_AUTHOR("Deepak Saxena");
index 2b4c5058787d76426b536d304374cb82ae92b82d,10f681f39c96292bfb224db69de6098234f99baf..1aa0447c5e66a2430ec9dd42bf5b86fba8549f16
@@@ -1,11 -1,11 +1,11 @@@
  /*
-  * $Id: lubbock-flash.c,v 1.19 2004/11/04 13:24:15 gleixner Exp $
+  * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
   *
   * Map driver for the Lubbock developer platform.
   *
   * Author:    Nicolas Pitre
   * Copyright: (C) 2001 MontaVista Software Inc.
-  * 
+  *
   * 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.
@@@ -76,7 -76,7 +76,7 @@@ static int __init init_lubbock(void
        int flashboot = (LUB_CONF_SWITCHES & 1);
        int ret = 0, i;
  
-       lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = 
+       lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
                (BOOT_DEF & 1) ? 2 : 4;
  
        /* Compensate for the nROMBT switch which swaps the flash banks */
                simple_map_init(&lubbock_maps[i]);
  
                printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
-                      lubbock_maps[i].name, lubbock_maps[i].phys, 
+                      lubbock_maps[i].name, lubbock_maps[i].phys,
                       lubbock_maps[i].bankwidth * 8);
  
                mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-               
                if (!mymtds[i]) {
                        iounmap((void *)lubbock_maps[i].virt);
                        if (lubbock_maps[i].cached)
  
        if (!mymtds[0] && !mymtds[1])
                return ret;
-       
        for (i = 0; i < 2; i++) {
                if (!mymtds[i]) {
                        printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
@@@ -151,14 -151,15 +151,14 @@@ static void __exit cleanup_lubbock(void
                if (nr_parsed_parts[i] || !i)
                        del_mtd_partitions(mymtds[i]);
                else
-                       del_mtd_device(mymtds[i]);                      
+                       del_mtd_device(mymtds[i]);
  
                map_destroy(mymtds[i]);
                iounmap((void *)lubbock_maps[i].virt);
                if (lubbock_maps[i].cached)
                        iounmap(lubbock_maps[i].cached);
  
 -              if (parsed_parts[i])
 -                      kfree(parsed_parts[i]);
 +              kfree(parsed_parts[i]);
        }
  }
  
index 763304154a923364151b7b4b789bf7db2e0ebbff,a88ed6691caf28f9ea09799cd7c1fe5f01c62c39..dc37652700570e3c6899fb881f1269fc17e8d270
@@@ -5,7 -5,7 +5,7 @@@
   *
   *  (C) 2002 MontVista Software, Inc.
   *
-  * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $
+  * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $
   */
  
  #include <linux/config.h>
@@@ -38,7 -38,7 +38,7 @@@ static struct map_info omap_toto_map_fl
        .virt =         (void __iomem *)OMAP_TOTO_FLASH_BASE,
  };
  
-  
  static struct mtd_partition toto_flash_partitions[] = {
        {
                .name =         "BootLoader",
                .name =         "EnvArea",      /* bottom 64KiB for env vars */
                .size =         MTDPART_SIZ_FULL,
                .offset =       MTDPART_OFS_APPEND,
-       } 
+       }
  };
  
  static struct mtd_partition *parsed_parts;
  
  static struct mtd_info *flash_mtd;
-  
- static int __init init_flash (void)   
+ static int __init init_flash (void)
  {
  
        struct mtd_partition *parts;
        int nb_parts = 0;
        int parsed_nr_parts = 0;
        const char *part_type;
-  
        /*
         * Static partition definition selection
         */
@@@ -89,7 -89,7 +89,7 @@@
        flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash);
        if (!flash_mtd)
                return -ENXIO;
-  
        if (parsed_nr_parts > 0) {
                parts = parsed_parts;
                nb_parts = parsed_nr_parts;
        }
        return 0;
  }
-  
- int __init omap_toto_mtd_init(void)  
+ int __init omap_toto_mtd_init(void)
  {
        int status;
  
      return status;
  }
  
- static void  __exit omap_toto_mtd_cleanup(void)  
+ static void  __exit omap_toto_mtd_cleanup(void)
  {
        if (flash_mtd) {
                del_mtd_partitions(flash_mtd);
                map_destroy(flash_mtd);
 -              if (parsed_parts)
 -                      kfree(parsed_parts);
 +              kfree(parsed_parts);
        }
  }
  
index a31f6ee8a4be5834d5d2f7ff9b583c236ba121f1,92cf158abb1f610ebc4c629c2fafa9e30d7f6949..9e8bb1782be00318ab3eb58264ccf087e3761c8d
@@@ -1,9 -1,9 +1,9 @@@
  /*
   * Flash memory access on SA11x0 based devices
-  * 
+  *
   * (C) 2000 Nicolas Pitre <nico@cam.org>
-  * 
-  * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
+  *
+  * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $
   */
  #include <linux/config.h>
  #include <linux/module.h>
@@@ -241,7 -241,8 +241,7 @@@ static void sa1100_destroy(struct sa_in
  #endif
        }
  
 -      if (info->parts)
 -              kfree(info->parts);
 +      kfree(info->parts);
  
        for (i = info->num_subdev - 1; i >= 0; i--)
                sa1100_destroy_subdev(&info->subdev[i]);
index 1355c28f90a4d7432a59171a9622dfc710a92dea,47941fbe74f6654e0a734fa0de44324dffcde5ae..0758cb1d01056568dfda74d55297f7e9a6daa791
@@@ -1,4 -1,4 +1,4 @@@
- /* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $
+ /* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $
   *
   * sun_uflash - Driver implementation for user-programmable flash
   * present on many Sun Microsystems SME boardsets.
@@@ -63,7 -63,7 +63,7 @@@ int uflash_devinit(struct linux_ebus_de
        iTmp = prom_getproperty(
                edev->prom_node, "reg", (void *)regs, sizeof(regs));
        if ((iTmp % sizeof(regs[0])) != 0) {
-               printk("%s: Strange reg property size %d\n", 
+               printk("%s: Strange reg property size %d\n",
                        UFLASH_DEVNAME, iTmp);
                return -ENODEV;
        }
@@@ -75,7 -75,7 +75,7 @@@
                 * can work on supporting it.
                 */
                printk("%s: unsupported device at 0x%lx (%d regs): " \
-                       "email ebrower@usa.net\n", 
+                       "email ebrower@usa.net\n",
                        UFLASH_DEVNAME, edev->resource[0].start, nregs);
                return -ENODEV;
        }
@@@ -84,7 -84,7 +84,7 @@@
                printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
                return(-ENOMEM);
        }
-       
        /* copy defaults and tweak parameters */
        memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
        pdev->map.size = regs[0].reg_size;
@@@ -155,7 -155,7 +155,7 @@@ static void __exit uflash_cleanup(void
  
        list_for_each(udevlist, &device_list) {
                udev = list_entry(udevlist, struct uflash_dev, list);
-               DEBUG(2, "%s: removing device %s\n", 
+               DEBUG(2, "%s: removing device %s\n",
                        UFLASH_DEVNAME, udev->name);
  
                if(0 != udev->mtd) {
                        iounmap(udev->map.virt);
                        udev->map.virt = NULL;
                }
 -              if(0 != udev->name) {
 -                      kfree(udev->name);
 -              }
 +              kfree(udev->name);
                kfree(udev);
-       }       
+       }
  }
  
  module_init(uflash_init);
index 0aca8179f27f676f022a6efb5eed81cd9a9412aa,9cb5d679fe6d640e03923587029309bd0d931ffc..a43517053e7cfe4819a51f0c1974ffc767ef8251
@@@ -1,15 -1,15 +1,15 @@@
  /*
-  * Handle mapping of the flash memory access routines 
+  * Handle mapping of the flash memory access routines
   * on TQM8xxL based devices.
   *
-  * $Id: tqm8xxl.c,v 1.13 2004/10/20 22:21:53 dwmw2 Exp $
+  * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $
   *
   * based on rpxlite.c
   *
   * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw>
   *
   * This code is GPLed
-  * 
+  *
   */
  
  /*
@@@ -19,7 -19,7 +19,7 @@@
   *        2MiB           512Kx16        2MiB             0
   *        4MiB           1Mx16          4MiB             0
   *        8MiB           1Mx16          4MiB             4MiB
-  * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at 
+  * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
   * kernel configuration.
   */
  #include <linux/config.h>
@@@ -58,9 -58,9 +58,9 @@@ static void __iomem *start_scan_addr
   * Here are partition information for all known TQM8xxL series devices.
   * See include/linux/mtd/partitions.h for definition of the mtd_partition
   * structure.
-  * 
+  *
   * The *_max_flash_size is the maximum possible mapped flash size which
-  * is not necessarily the actual flash size.  It must correspond to the 
+  * is not necessarily the actual flash size.  It must correspond to the
   * value specified in the mapping definition defined by the
   * "struct map_desc *_io_desc" for the corresponding machine.
   */
@@@ -132,9 -132,9 +132,9 @@@ int __init init_tqm_mtd(void
        for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
                if(mtd_size >= flash_size)
                        break;
-               
                printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
-               
                map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
                if(map_banks[idx] == NULL) {
                        ret = -ENOMEM;
                        mtd_size += mtd_banks[idx]->size;
                        num_banks++;
  
-                       printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, 
+                       printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
                        mtd_banks[idx]->name, mtd_banks[idx]->size);
                }
        }
                } else {
                        printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n",
                                        idx, part_banks[idx].type);
-                       add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, 
+                       add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part,
                                                                part_banks[idx].nums);
                }
        }
  error_mem:
        for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
                if(map_banks[idx] != NULL) {
 -                      if(map_banks[idx]->name != NULL) {
 -                              kfree(map_banks[idx]->name);
 -                              map_banks[idx]->name = NULL;
 -                      }
 +                      kfree(map_banks[idx]->name);
 +                      map_banks[idx]->name = NULL;
                        kfree(map_banks[idx]);
                        map_banks[idx] = NULL;
                }
index 8e78d7b96a5671af16033227e4582e694e502438,4673ba79309b152c78fa6e4f609484ce420534e8..5d222460b42a87acd20c18f23183c67ad9f109e4
@@@ -5,14 -5,14 +5,14 @@@
   *   This is the generic MTD driver for NAND flash devices. It should be
   *   capable of working with almost all NAND chips currently available.
   *   Basic support for AG-AND chips is provided.
-  *   
+  *
   *    Additional technical information is available on
   *    http://www.linux-mtd.infradead.org/tech/nand.html
-  *    
+  *
   *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
   *              2002 Thomas Gleixner (tglx@linutronix.de)
   *
-  *  02-08-2004  tglx: support for strange chips, which cannot auto increment 
+  *  02-08-2004  tglx: support for strange chips, which cannot auto increment
   *            pages on read / read_oob
   *
   *  03-17-2004  tglx: Check ready before auto increment check. Simon Bayes
@@@ -21,7 -21,7 +21,7 @@@
   *            Make reads over block boundaries work too
   *
   *  04-14-2004        tglx: first working version for 2k page size chips
-  *  
+  *
   *  05-19-2004  tglx: Basic support for Renesas AG-AND chips
   *
   *  09-24-2004  tglx: add support for hardware controllers (e.g. ECC) shared
   *
   *  12-05-2004        dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
   *            Basically, any block not rewritten may lose data when surrounding blocks
-  *            are rewritten many times.  JFFS2 ensures this doesn't happen for blocks 
+  *            are rewritten many times.  JFFS2 ensures this doesn't happen for blocks
   *            it uses, but the Bad Block Table(s) may not be rewritten.  To ensure they
   *            do not lose data, force them to be rewritten when some of the surrounding
-  *            blocks are erased.  Rather than tracking a specific nearby block (which 
-  *            could itself go bad), use a page address 'mask' to select several blocks 
+  *            blocks are erased.  Rather than tracking a specific nearby block (which
+  *            could itself go bad), use a page address 'mask' to select several blocks
   *            in the same area, and rewrite the BBT when any of them are erased.
   *
-  *  01-03-2005        dmarlin: added support for the device recovery command sequence for Renesas 
+  *  01-03-2005        dmarlin: added support for the device recovery command sequence for Renesas
   *            AG-AND chips.  If there was a sudden loss of power during an erase operation,
   *            a "device recovery" operation must be performed when power is restored
   *            to ensure correct operation.
   *
-  *  01-20-2005        dmarlin: added support for optional hardware specific callback routine to 
+  *  01-20-2005        dmarlin: added support for optional hardware specific callback routine to
   *            perform extra error status checks on erase and write failures.  This required
   *            adding a wrapper function for nand_read_ecc.
   *
+  * 08-20-2005 vwool: suspend/resume added
+  *
   * Credits:
-  *    David Woodhouse for adding multichip support  
-  *    
+  *    David Woodhouse for adding multichip support
+  *
   *    Aleph One Ltd. and Toby Churchill Ltd. for supporting the
   *    rework for 2K page size chips
   *
@@@ -59,7 -61,7 +61,7 @@@
   *    The AG-AND chips have nice features for speed improvement,
   *    which are not supported yet. Read / program 4 pages in one go.
   *
-  * $Id: nand_base.c,v 1.147 2005/07/15 07:18:06 gleixner Exp $
+  * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $
   *
   * 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
@@@ -103,8 -105,8 +105,8 @@@ static struct nand_oobinfo nand_oob_64 
        .useecc = MTD_NANDECC_AUTOPLACE,
        .eccbytes = 24,
        .eccpos = {
-               40, 41, 42, 43, 44, 45, 46, 47, 
-               48, 49, 50, 51, 52, 53, 54, 55, 
+               40, 41, 42, 43, 44, 45, 46, 47,
+               48, 49, 50, 51, 52, 53, 54, 55,
                56, 57, 58, 59, 60, 61, 62, 63},
        .oobfree = { {2, 38} }
  };
@@@ -147,19 -149,19 +149,19 @@@ static void nand_sync (struct mtd_info 
  static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,
                struct nand_oobinfo *oobsel, int mode);
  #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
+ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
        u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
  #else
  #define nand_verify_pages(...) (0)
  #endif
-               
- static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
+ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
  
  /**
   * nand_release_device - [GENERIC] release chip
   * @mtd:      MTD device structure
-  * 
-  * Deselect, release chip lock and wake up anyone waiting on the device 
+  *
+  * Deselect, release chip lock and wake up anyone waiting on the device
   */
  static void nand_release_device (struct mtd_info *mtd)
  {
@@@ -213,7 -215,7 +215,7 @@@ static void nand_write_byte(struct mtd_
   * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
   * @mtd:      MTD device structure
   *
-  * Default read function for 16bit buswith with 
+  * Default read function for 16bit buswith with
   * endianess conversion
   */
  static u_char nand_read_byte16(struct mtd_info *mtd)
@@@ -240,7 -242,7 +242,7 @@@ static void nand_write_byte16(struct mt
   * nand_read_word - [DEFAULT] read one word from the chip
   * @mtd:      MTD device structure
   *
-  * Default read function for 16bit buswith without 
+  * Default read function for 16bit buswith without
   * endianess conversion
   */
  static u16 nand_read_word(struct mtd_info *mtd)
   * @mtd:      MTD device structure
   * @word:     data word to write
   *
-  * Default write function for 16bit buswith without 
+  * Default write function for 16bit buswith without
   * endianess conversion
   */
  static void nand_write_word(struct mtd_info *mtd, u16 word)
@@@ -275,7 -277,7 +277,7 @@@ static void nand_select_chip(struct mtd
        struct nand_chip *this = mtd->priv;
        switch(chip) {
        case -1:
-               this->hwcontrol(mtd, NAND_CTL_CLRNCE);  
+               this->hwcontrol(mtd, NAND_CTL_CLRNCE);
                break;
        case 0:
                this->hwcontrol(mtd, NAND_CTL_SETNCE);
@@@ -304,7 -306,7 +306,7 @@@ static void nand_write_buf(struct mtd_i
  }
  
  /**
-  * nand_read_buf - [DEFAULT] read chip data into buffer 
+  * nand_read_buf - [DEFAULT] read chip data into buffer
   * @mtd:      MTD device structure
   * @buf:      buffer to store date
   * @len:      number of bytes to read
@@@ -321,7 -323,7 +323,7 @@@ static void nand_read_buf(struct mtd_in
  }
  
  /**
-  * nand_verify_buf - [DEFAULT] Verify chip data against buffer 
+  * nand_verify_buf - [DEFAULT] Verify chip data against buffer
   * @mtd:      MTD device structure
   * @buf:      buffer containing the data to compare
   * @len:      number of bytes to compare
@@@ -354,14 -356,14 +356,14 @@@ static void nand_write_buf16(struct mtd
        struct nand_chip *this = mtd->priv;
        u16 *p = (u16 *) buf;
        len >>= 1;
-       
        for (i=0; i<len; i++)
                writew(p[i], this->IO_ADDR_W);
-               
  }
  
  /**
-  * nand_read_buf16 - [DEFAULT] read chip data into buffer 
+  * nand_read_buf16 - [DEFAULT] read chip data into buffer
   * @mtd:      MTD device structure
   * @buf:      buffer to store date
   * @len:      number of bytes to read
@@@ -380,7 -382,7 +382,7 @@@ static void nand_read_buf16(struct mtd_
  }
  
  /**
-  * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer 
+  * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
   * @mtd:      MTD device structure
   * @buf:      buffer containing the data to compare
   * @len:      number of bytes to compare
@@@ -407,7 -409,7 +409,7 @@@ static int nand_verify_buf16(struct mtd
   * @ofs:      offset from device start
   * @getchip:  0, if the chip is already selected
   *
-  * Check, if the block is bad. 
+  * Check, if the block is bad.
   */
  static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
  {
  
                /* Select the NAND device */
                this->select_chip(mtd, chipnr);
-       } else 
-               page = (int) ofs;       
+       } else
+               page = (int) ofs;
  
        if (this->options & NAND_BUSWIDTH_16) {
                this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
                bad = cpu_to_le16(this->read_word(mtd));
                if (this->badblockpos & 0x1)
-                       bad >>= 1;
+                       bad >>= 8;
                if ((bad & 0xFF) != 0xff)
                        res = 1;
        } else {
                if (this->read_byte(mtd) != 0xff)
                        res = 1;
        }
-               
        if (getchip) {
                /* Deselect and wake up anyone waiting on the device */
                nand_release_device(mtd);
-       }       
-       
+       }
        return res;
  }
  
@@@ -462,7 -464,7 +464,7 @@@ static int nand_default_block_markbad(s
        u_char buf[2] = {0, 0};
        size_t  retlen;
        int block;
-       
        /* Get block number */
        block = ((int) ofs) >> this->bbt_erase_shift;
        if (this->bbt)
        /* Do we have a flash based bad block table ? */
        if (this->options & NAND_USE_FLASH_BBT)
                return nand_update_bbt (mtd, ofs);
-               
        /* We write two bytes, so we dont have to mess with 16 bit access */
        ofs += mtd->oobsize + (this->badblockpos & ~0x01);
        return nand_write_oob (mtd, ofs , 2, &retlen, buf);
  }
  
- /** 
+ /**
   * nand_check_wp - [GENERIC] check if the chip is write protected
   * @mtd:      MTD device structure
-  * Check, if the device is write protected 
+  * Check, if the device is write protected
   *
-  * The function expects, that the device is already selected 
+  * The function expects, that the device is already selected
   */
  static int nand_check_wp (struct mtd_info *mtd)
  {
        struct nand_chip *this = mtd->priv;
        /* Check the WP bit */
        this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; 
+       return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
  }
  
  /**
  static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
  {
        struct nand_chip *this = mtd->priv;
-       
        if (!this->bbt)
                return this->block_bad(mtd, ofs, getchip);
-       
        /* Return info from the table */
        return nand_isbad_bbt (mtd, ofs, allowbbt);
  }
  
- /* 
+ /*
   * Wait for the ready pin, after a command
   * The timeout is catched later.
   */
@@@ -527,7 -529,7 +529,7 @@@ static void nand_wait_ready(struct mtd_
                if (this->dev_ready(mtd))
                        return;
                touch_softlockup_watchdog();
-       } while (time_before(jiffies, timeo));  
+       } while (time_before(jiffies, timeo));
  }
  
  /**
@@@ -590,13 -592,13 +592,13 @@@ static void nand_command (struct mtd_in
                /* Latch in address */
                this->hwcontrol(mtd, NAND_CTL_CLRALE);
        }
-       
-       /* 
-        * program and erase have their own busy handlers 
+       /*
+        * program and erase have their own busy handlers
         * status and sequential in needs no delay
        */
        switch (command) {
-                       
        case NAND_CMD_PAGEPROG:
        case NAND_CMD_ERASE1:
        case NAND_CMD_ERASE2:
                return;
  
        case NAND_CMD_RESET:
-               if (this->dev_ready)    
+               if (this->dev_ready)
                        break;
                udelay(this->chip_delay);
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
                while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
                return;
  
-       /* This applies to read commands */     
+       /* This applies to read commands */
        default:
-               /* 
+               /*
                 * If we don't have access to the busy pin, we apply the given
                 * command delay
                */
                if (!this->dev_ready) {
                        udelay (this->chip_delay);
                        return;
-               }       
+               }
        }
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
@@@ -653,8 -655,8 +655,8 @@@ static void nand_command_lp (struct mtd
                column += mtd->oobblock;
                command = NAND_CMD_READ0;
        }
-       
-               
        /* Begin command latch cycle */
        this->hwcontrol(mtd, NAND_CTL_SETCLE);
        /* Write out the command to the device. */
                                column >>= 1;
                        this->write_byte(mtd, column & 0xff);
                        this->write_byte(mtd, column >> 8);
-               }       
+               }
                if (page_addr != -1) {
                        this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
                        this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
                /* Latch in address */
                this->hwcontrol(mtd, NAND_CTL_CLRALE);
        }
-       
-       /* 
-        * program and erase have their own busy handlers 
+       /*
+        * program and erase have their own busy handlers
         * status, sequential in, and deplete1 need no delay
         */
        switch (command) {
-                       
        case NAND_CMD_CACHEDPROG:
        case NAND_CMD_PAGEPROG:
        case NAND_CMD_ERASE1:
        case NAND_CMD_DEPLETE1:
                return;
  
-       /* 
+       /*
         * read error status commands require only a short delay
         */
        case NAND_CMD_STATUS_ERROR:
                return;
  
        case NAND_CMD_RESET:
-               if (this->dev_ready)    
+               if (this->dev_ready)
                        break;
                udelay(this->chip_delay);
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
                /* End command latch cycle */
                this->hwcontrol(mtd, NAND_CTL_CLRCLE);
                /* Fall through into ready check */
-               
-       /* This applies to read commands */     
+       /* This applies to read commands */
        default:
-               /* 
+               /*
                 * If we don't have access to the busy pin, we apply the given
                 * command delay
                */
                if (!this->dev_ready) {
                        udelay (this->chip_delay);
                        return;
-               }       
+               }
        }
  
        /* Apply this short delay always to ensure that we do wait tWB in
   * nand_get_device - [GENERIC] Get chip for selected access
   * @this:     the nand chip descriptor
   * @mtd:      MTD device structure
-  * @new_state:        the state which is requested 
+  * @new_state:        the state which is requested
   *
   * Get the device and lock it for exclusive access
   */
- static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
  {
        struct nand_chip *active;
        spinlock_t *lock;
@@@ -779,7 -781,11 +781,11 @@@ retry
        if (active == this && this->state == FL_READY) {
                this->state = new_state;
                spin_unlock(lock);
-               return;
+               return 0;
+       }
+       if (new_state == FL_PM_SUSPENDED) {
+               spin_unlock(lock);
+               return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
        }
        set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(wq, &wait);
   * @state:    state to select the max. timeout value
   *
   * Wait for command done. This applies to erase and program only
-  * Erase can take up to 400ms and program up to 20ms according to 
+  * Erase can take up to 400ms and program up to 20ms according to
   * general NAND and SmartMedia specs
   *
  */
@@@ -805,7 -811,7 +811,7 @@@ static int nand_wait(struct mtd_info *m
  
        unsigned long   timeo = jiffies;
        int     status;
-       
        if (state == FL_ERASING)
                 timeo += (HZ * 400) / 1000;
        else
  
        if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
                this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);
-       else    
+       else
                this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
  
-       while (time_before(jiffies, timeo)) {           
+       while (time_before(jiffies, timeo)) {
                /* Check, if we were interrupted */
                if (this->state != state)
                        return 0;
  
                if (this->dev_ready) {
                        if (this->dev_ready(mtd))
-                               break;  
+                               break;
                } else {
                        if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
   *
   * Cached programming is not supported yet.
   */
- static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, 
+ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page,
        u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached)
  {
        int     i, status;
        int     *oob_config = oobsel->eccpos;
        int     datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
        int     eccbytes = 0;
-       
        /* FIXME: Enable cached programming */
        cached = 0;
-       
        /* Send command to begin auto page programming */
        this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
  
                printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
                this->write_buf(mtd, this->data_poi, mtd->oobblock);
                break;
-               
        /* Software ecc 3/256, write all */
        case NAND_ECC_SOFT:
                for (; eccsteps; eccsteps--) {
                }
                break;
        }
-                                                                               
        /* Write out OOB data */
        if (this->options & NAND_HWECC_SYNDROME)
                this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
-       else 
+       else
                this->write_buf(mtd, oob_buf, mtd->oobsize);
  
        /* Send command to actually program the data */
                /* wait until cache is ready*/
                // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
        }
-       return 0;       
+       return 0;
  }
  
  #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
   * @oobmode:  1 = full buffer verify, 0 = ecc only
   *
   * The NAND device assumes that it is always writing to a cleanly erased page.
-  * Hence, it performs its internal write verification only on bits that 
+  * Hence, it performs its internal write verification only on bits that
   * transitioned from 1 to 0. The device does NOT verify the whole page on a
-  * byte by byte basis. It is possible that the page was not completely erased 
-  * or the page is becoming unusable due to wear. The read with ECC would catch 
-  * the error later when the ECC page check fails, but we would rather catch 
+  * byte by byte basis. It is possible that the page was not completely erased
+  * or the page is becoming unusable due to wear. The read with ECC would catch
+  * the error later when the ECC page check fails, but we would rather catch
   * it early in the page write stage. Better to write no data than invalid data.
   */
- static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
+ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
        u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
  {
        int     i, j, datidx = 0, oobofs = 0, res = -EIO;
        int     eccsteps = this->eccsteps;
-       int     hweccbytes; 
+       int     hweccbytes;
        u_char  oobdata[64];
  
        hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
  
                        if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
                                int ecccnt = oobsel->eccbytes;
-               
                                for (i = 0; i < ecccnt; i++) {
                                        int idx = oobsel->eccpos[i];
                                        if (oobdata[idx] != oob_buf[oobofs + idx] ) {
                                                goto out;
                                        }
                                }
-                       }       
+                       }
                }
                oobofs += mtd->oobsize - hweccbytes * eccsteps;
                page++;
                numpages--;
  
-               /* Apply delay or wait for ready/busy pin 
+               /* Apply delay or wait for ready/busy pin
                 * Do this before the AUTOINCR check, so no problems
                 * arise if a chip which does auto increment
                 * is marked as NOAUTOINCR by the board driver.
                 * Do this also before returning, so the chip is
                 * ready for the next command.
                */
-               if (!this->dev_ready) 
+               if (!this->dev_ready)
                        udelay (this->chip_delay);
                else
                        nand_wait_ready(mtd);
                /* All done, return happy */
                if (!numpages)
                        return 0;
-               
-                       
-               /* Check, if the chip supports auto page increment */ 
+               /* Check, if the chip supports auto page increment */
                if (!NAND_CANAUTOINCR(this))
                        this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
        }
-       /* 
+       /*
         * Terminate the read command. We come here in case of an error
         * So we must issue a reset command.
         */
- out:   
+ out:
        this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
        return res;
  }
@@@ -1105,7 -1111,7 +1111,7 @@@ static int nand_read_ecc (struct mtd_in
   * NAND read with ECC
   */
  int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-                            size_t * retlen, u_char * buf, u_char * oob_buf, 
+                            size_t * retlen, u_char * buf, u_char * oob_buf,
                             struct nand_oobinfo *oobsel, int flags)
  {
  
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
-               
        eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
        oob_config = oobsel->eccpos;
  
        end = mtd->oobblock;
        ecc = this->eccsize;
        eccbytes = this->eccbytes;
-       
        if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
                compareecc = 0;
  
        oobreadlen = mtd->oobsize;
-       if (this->options & NAND_HWECC_SYNDROME) 
+       if (this->options & NAND_HWECC_SYNDROME)
                oobreadlen -= oobsel->eccbytes;
  
        /* Loop until all data read */
        while (read < len) {
-               
                int aligned = (!col && (len - read) >= end);
-               /* 
+               /*
                 * If the read is not page aligned, we have to read into data buffer
                 * due to ecc, else we read into return buffer direct
                 */
                if (aligned)
                        data_poi = &buf[read];
-               else 
+               else
                        data_poi = this->data_buf;
-               
-               /* Check, if we have this page in the buffer 
+               /* Check, if we have this page in the buffer
                 *
                 * FIXME: Make it work when we must provide oob data too,
                 * check the usage of data_buf oob field
                if (sndcmd) {
                        this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
                        sndcmd = 0;
-               }       
+               }
  
                /* get oob area, if we have no oob buffer from fs-driver */
                if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
                        oob_data = &this->data_buf[end];
  
                eccsteps = this->eccsteps;
-               
                switch (eccmode) {
                case NAND_ECC_NONE: {   /* No ECC, Read in a page */
                        static unsigned long lastwhinge = 0;
                        this->read_buf(mtd, data_poi, end);
                        break;
                }
-                       
                case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
                        this->read_buf(mtd, data_poi, end);
-                       for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 
+                       for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc)
                                this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
-                       break;  
+                       break;
  
                default:
                        for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
                                         * does the error correction on the fly */
                                        ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
                                        if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
-                                               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 
+                                               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
                                                        "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
                                                ecc_failed++;
                                        }
                                } else {
                                        this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
-                               }       
+                               }
                        }
-                       break;                                          
+                       break;
                }
  
                /* read oobdata */
  
                /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
                if (!compareecc)
-                       goto readoob;   
-               
+                       goto readoob;
                /* Pick the ECC bytes out of the oob data */
                for (j = 0; j < oobsel->eccbytes; j++)
                        ecc_code[j] = oob_data[oob_config[j]];
                /* correct data, if neccecary */
                for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
                        ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
-                       
                        /* Get next chunk of ecc bytes */
                        j += eccbytes;
-                       
-                       /* Check, if we have a fs supplied oob-buffer, 
+                       /* Check, if we have a fs supplied oob-buffer,
                         * This is the legacy mode. Used by YAFFS1
                         * Should go away some day
                         */
-                       if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { 
+                       if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
                                int *p = (int *)(&oob_data[mtd->oobsize]);
                                p[i] = ecc_status;
                        }
-                       
-                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {     
+                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
                                DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
                                ecc_failed++;
                        }
-               }               
+               }
  
        readoob:
                /* check, if we have a fs supplied oob-buffer */
                }
        readdata:
                /* Partial page read, transfer data into fs buffer */
-               if (!aligned) { 
+               if (!aligned) {
                        for (j = col; j < end && read < len; j++)
                                buf[read++] = data_poi[j];
-                       this->pagebuf = realpage;       
-               } else          
+                       this->pagebuf = realpage;
+               } else
                        read += mtd->oobblock;
  
-               /* Apply delay or wait for ready/busy pin 
+               /* Apply delay or wait for ready/busy pin
                 * Do this before the AUTOINCR check, so no problems
                 * arise if a chip which does auto increment
                 * is marked as NOAUTOINCR by the board driver.
                */
-               if (!this->dev_ready) 
+               if (!this->dev_ready)
                        udelay (this->chip_delay);
                else
                        nand_wait_ready(mtd);
-                       
                if (read == len)
-                       break;  
+                       break;
  
                /* For subsequent reads align to page boundary. */
                col = 0;
                        this->select_chip(mtd, -1);
                        this->select_chip(mtd, chipnr);
                }
-               /* Check, if the chip supports auto page increment 
-                * or if we have hit a block boundary. 
-               */ 
+               /* Check, if the chip supports auto page increment
+                * or if we have hit a block boundary.
+               */
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
-                       sndcmd = 1;                             
+                       sndcmd = 1;
        }
  
        /* Deselect and wake up anyone waiting on the device */
@@@ -1378,7 -1384,7 +1384,7 @@@ static int nand_read_oob (struct mtd_in
        /* Shift to get page */
        page = (int)(from >> this->page_shift);
        chipnr = (int)(from >> this->chip_shift);
-       
        /* Mask to get column */
        col = from & (mtd->oobsize - 1);
  
  
        /* Send the read command */
        this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask);
-       /* 
+       /*
         * Read the data, if we read more than one page
         * oob data, let the device transfer the data !
         */
                                this->select_chip(mtd, -1);
                                this->select_chip(mtd, chipnr);
                        }
-                               
-                       /* Apply delay or wait for ready/busy pin 
+                       /* Apply delay or wait for ready/busy pin
                         * Do this before the AUTOINCR check, so no problems
                         * arise if a chip which does auto increment
                         * is marked as NOAUTOINCR by the board driver.
                         */
-                       if (!this->dev_ready) 
+                       if (!this->dev_ready)
                                udelay (this->chip_delay);
                        else
                                nand_wait_ready(mtd);
  
-                       /* Check, if the chip supports auto page increment 
-                        * or if we have hit a block boundary. 
-                       */ 
+                       /* Check, if the chip supports auto page increment
+                        * or if we have hit a block boundary.
+                       */
                        if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
                                /* For subsequent page reads set offset to 0 */
                                this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
@@@ -1481,27 -1487,27 +1487,27 @@@ int nand_read_raw (struct mtd_info *mtd
        nand_get_device (this, mtd , FL_READING);
  
        this->select_chip (mtd, chip);
-       
        /* Add requested oob length */
        len += ooblen;
-       
        while (len) {
                if (sndcmd)
                        this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);
-               sndcmd = 0;     
+               sndcmd = 0;
  
                this->read_buf (mtd, &buf[cnt], pagesize);
  
                len -= pagesize;
                cnt += pagesize;
                page++;
-               
-               if (!this->dev_ready) 
+               if (!this->dev_ready)
                        udelay (this->chip_delay);
                else
                        nand_wait_ready(mtd);
-                       
-               /* Check, if the chip supports auto page increment */ 
+               /* Check, if the chip supports auto page increment */
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
                        sndcmd = 1;
        }
  }
  
  
- /** 
-  * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer 
+ /**
+  * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
   * @mtd:      MTD device structure
   * @fsbuf:    buffer given by fs driver
   * @oobsel:   out of band selection structre
@@@ -1542,20 -1548,20 +1548,20 @@@ static u_char * nand_prepare_oobbuf (st
        int i, len, ofs;
  
        /* Zero copy fs supplied buffer */
-       if (fsbuf && !autoplace) 
+       if (fsbuf && !autoplace)
                return fsbuf;
  
        /* Check, if the buffer must be filled with ff again */
-       if (this->oobdirty) {   
-               memset (this->oob_buf, 0xff, 
+       if (this->oobdirty) {
+               memset (this->oob_buf, 0xff,
                        mtd->oobsize << (this->phys_erase_shift - this->page_shift));
                this->oobdirty = 0;
-       }       
-       
+       }
        /* If we have no autoplacement or no fs buffer use the internal one */
        if (!autoplace || !fsbuf)
                return this->oob_buf;
-       
        /* Walk through the pages and place the data */
        this->oobdirty = 1;
        ofs = 0;
@@@ -1589,7 -1595,7 +1595,7 @@@ static int nand_write (struct mtd_info 
  {
        return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
  }
-                          
  /**
   * nand_write_ecc - [MTD Interface] NAND write with ECC
   * @mtd:      MTD device structure
@@@ -1622,7 -1628,7 +1628,7 @@@ static int nand_write_ecc (struct mtd_i
                return -EINVAL;
        }
  
-       /* reject writes, which are not page aligned */ 
+       /* reject writes, which are not page aligned */
        if (NOTALIGNED (to) || NOTALIGNED(len)) {
                printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
                return -EINVAL;
                goto out;
  
        /* if oobsel is NULL, use chip defaults */
-       if (oobsel == NULL) 
-               oobsel = &mtd->oobinfo;         
-               
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
                oobsel = this->autooob;
                autoplace = 1;
-       }       
+       }
        if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                autoplace = 1;
  
        totalpages = len >> this->page_shift;
        page = (int) (to >> this->page_shift);
        /* Invalidate the page cache, if we write to the cached page */
-       if (page <= this->pagebuf && this->pagebuf < (page + totalpages))  
+       if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
                this->pagebuf = -1;
-       
        /* Set it relative to chip */
        page &= this->pagemask;
        startpage = page;
                if (ret) {
                        DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
                        goto out;
-               }       
+               }
                /* Next oob page */
                oob += mtd->oobsize;
                /* Update written bytes count */
                written += mtd->oobblock;
-               if (written == len) 
+               if (written == len)
                        goto cmp;
-               
                /* Increment page address */
                page++;
  
                if (!(page & (ppblock - 1))){
                        int ofs;
                        this->data_poi = bufstart;
-                       ret = nand_verify_pages (mtd, this, startpage, 
+                       ret = nand_verify_pages (mtd, this, startpage,
                                page - startpage,
                                oobbuf, oobsel, chipnr, (eccbuf != NULL));
                        if (ret) {
                                DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
                                goto out;
-                       }       
+                       }
                        *retlen = written;
  
                        ofs = autoplace ? mtd->oobavail : mtd->oobsize;
                        numpages = min (totalpages, ppblock);
                        page &= this->pagemask;
                        startpage = page;
-                       oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, 
+                       oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel,
                                        autoplace, numpages);
+                       oob = 0;
                        /* Check, if we cross a chip boundary */
                        if (!page) {
                                chipnr++;
@@@ -1731,7 -1738,7 +1738,7 @@@ cmp
                oobbuf, oobsel, chipnr, (eccbuf != NULL));
        if (!ret)
                *retlen = written;
-       else    
+       else
                DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
  
  out:
@@@ -1791,7 -1798,7 +1798,7 @@@ static int nand_write_oob (struct mtd_i
        /* Check, if it is write protected */
        if (nand_check_wp(mtd))
                goto out;
-       
        /* Invalidate the page cache, if we write to the cached page */
        if (page == this->pagebuf)
                this->pagebuf = -1;
   *
   * NAND write with kvec. This just calls the ecc function
   */
- static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
+ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
                loff_t to, size_t * retlen)
  {
-       return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));    
+       return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));
  }
  
  /**
   *
   * NAND write with iovec with ecc
   */
- static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
+ static int nand_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)
  {
        int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
                return -EINVAL;
        }
  
-       /* reject writes, which are not page aligned */ 
+       /* reject writes, which are not page aligned */
        if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
                printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
                return -EINVAL;
                goto out;
  
        /* if oobsel is NULL, use chip defaults */
-       if (oobsel == NULL) 
-               oobsel = &mtd->oobinfo;         
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
  
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
                oobsel = this->autooob;
                autoplace = 1;
-       }       
+       }
        if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                autoplace = 1;
  
        /* Setup start page */
        page = (int) (to >> this->page_shift);
        /* Invalidate the page cache, if we write to the cached page */
-       if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))  
+       if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
                this->pagebuf = -1;
  
        startpage = page & this->pagemask;
                        oob = 0;
                        for (i = 1; i <= numpages; i++) {
                                /* Write one page. If this is the last page to write
-                                * then use the real pageprogram command, else select 
+                                * then use the real pageprogram command, else select
                                 * cached programming if supported by the chip.
                                 */
-                               ret = nand_write_page (mtd, this, page & this->pagemask, 
+                               ret = nand_write_page (mtd, this, page & this->pagemask,
                                        &oobbuf[oob], oobsel, i != numpages);
                                if (ret)
                                        goto out;
                                count--;
                        }
                } else {
-                       /* We must use the internal buffer, read data out of each 
+                       /* We must use the internal buffer, read data out of each
                         * tuple until we have a full page to write
                         */
                        int cnt = 0;
                        while (cnt < mtd->oobblock) {
-                               if (vecs->iov_base != NULL && vecs->iov_len) 
+                               if (vecs->iov_base != NULL && vecs->iov_len)
                                        this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
                                /* Check, if we have to switch to the next tuple */
                                if (len >= (int) vecs->iov_len) {
                                        count--;
                                }
                        }
-                       this->pagebuf = page;   
-                       this->data_poi = this->data_buf;        
+                       this->pagebuf = page;
+                       this->data_poi = this->data_buf;
                        bufstart = this->data_poi;
-                       numpages = 1;           
+                       numpages = 1;
                        oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
                        ret = nand_write_page (mtd, this, page & this->pagemask,
                                oobbuf, oobsel, 0);
                ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
                if (ret)
                        goto out;
-                       
                written += mtd->oobblock * numpages;
                /* All done ? */
                if (!count)
@@@ -2072,7 -2079,7 +2079,7 @@@ static int nand_erase (struct mtd_info 
  {
        return nand_erase_nand (mtd, instr, 0);
  }
-  
  #define BBT_PAGE_MASK 0xffffff3f
  /**
   * nand_erase_intern - [NAND Interface] erase block(s)
@@@ -2154,14 -2161,14 +2161,14 @@@ int nand_erase_nand (struct mtd_info *m
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
                }
-               
-               /* Invalidate the page cache, if we erase the block which contains 
+               /* Invalidate the page cache, if we erase the block which contains
                   the current cached page */
                if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
                        this->pagebuf = -1;
  
                this->erase_cmd (mtd, page & this->pagemask);
-               
                status = this->waitfunc (mtd, this, FL_ERASING);
  
                /* See if operation failed and additional status checks are available */
  
                /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
                if (this->options & BBT_AUTO_REFRESH) {
-                       if (((page & BBT_PAGE_MASK) == bbt_masked_page) && 
+                       if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
                             (page != this->bbt_td->pages[chipnr])) {
                                rewrite_bbt[chipnr] = (page << this->page_shift);
                        }
                }
-               
                /* Increment page address and decrement length */
                len -= (1 << this->phys_erase_shift);
                page += pages_per_block;
                        this->select_chip(mtd, -1);
                        this->select_chip(mtd, chipnr);
  
-                       /* if BBT requires refresh and BBT-PERCHIP, 
+                       /* if BBT requires refresh and BBT-PERCHIP,
                         *   set the BBT page mask to see if this BBT should be rewritten */
                        if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
                                bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
@@@ -2220,7 -2227,7 +2227,7 @@@ erase_exit
                for (chipnr = 0; chipnr < this->numchips; chipnr++) {
                        if (rewrite_bbt[chipnr]) {
                                /* update the BBT for chip */
-                               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", 
+                               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
                                        chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
                                nand_update_bbt (mtd, rewrite_bbt[chipnr]);
                        }
@@@ -2258,9 -2265,9 +2265,9 @@@ static void nand_sync (struct mtd_info 
  static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
  {
        /* Check for invalid offset */
-       if (ofs > mtd->size) 
+       if (ofs > mtd->size)
                return -EINVAL;
-       
        return nand_block_checkbad (mtd, ofs, 1, 0);
  }
  
@@@ -2284,6 -2291,34 +2291,34 @@@ static int nand_block_markbad (struct m
        return this->block_markbad(mtd, ofs);
  }
  
+ /**
+  * nand_suspend - [MTD Interface] Suspend the NAND flash
+  * @mtd:      MTD device structure
+  */
+ static int nand_suspend(struct mtd_info *mtd)
+ {
+       struct nand_chip *this = mtd->priv;
+       return nand_get_device (this, mtd, FL_PM_SUSPENDED);
+ }
+ /**
+  * nand_resume - [MTD Interface] Resume the NAND flash
+  * @mtd:      MTD device structure
+  */
+ static void nand_resume(struct mtd_info *mtd)
+ {
+       struct nand_chip *this = mtd->priv;
+       if (this->state == FL_PM_SUSPENDED)
+               nand_release_device(mtd);
+       else
+               printk(KERN_ERR "resume() called for the chip which is not "
+                               "in suspended state\n");
+ }
  /**
   * nand_scan - [NAND Interface] Scan for the NAND device
   * @mtd:      MTD device structure
@@@ -2351,13 -2386,13 +2386,13 @@@ int nand_scan (struct mtd_info *mtd, in
  
        /* Print and store flash device information */
        for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-                               
-               if (nand_dev_id != nand_flash_ids[i].id) 
+               if (nand_dev_id != nand_flash_ids[i].id)
                        continue;
  
                if (!mtd->name) mtd->name = nand_flash_ids[i].name;
                this->chipsize = nand_flash_ids[i].chipsize << 20;
-               
                /* New devices have all the information in additional id bytes */
                if (!nand_flash_ids[i].pagesize) {
                        int extid;
                        mtd->oobblock = 1024 << (extid & 0x3);
                        extid >>= 2;
                        /* Calc oobsize */
-                       mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
+                       mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
                        extid >>= 2;
                        /* Calc blocksize. Blocksize is multiples of 64KiB */
                        mtd->erasesize = (64 * 1024)  << (extid & 0x03);
                        extid >>= 2;
                        /* Get buswidth information */
                        busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-               
                } else {
                        /* Old devices have this data hardcoded in the
                         * device id table */
                 * this correct ! */
                if (busw != (this->options & NAND_BUSWIDTH_16)) {
                        printk (KERN_INFO "NAND device: Manufacturer ID:"
-                               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+                               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
                                nand_manuf_ids[maf_id].name , mtd->name);
-                       printk (KERN_WARNING 
-                               "NAND bus width %d instead %d bit\n", 
+                       printk (KERN_WARNING
+                               "NAND bus width %d instead %d bit\n",
                                        (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
                                        busw ? 16 : 8);
                        this->select_chip(mtd, -1);
-                       return 1;       
+                       return 1;
                }
-               
-               /* Calculate the address shift from the page size */    
+               /* Calculate the address shift from the page size */
                this->page_shift = ffs(mtd->oobblock) - 1;
                this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
                this->chip_shift = ffs(this->chipsize) - 1;
  
                /* Set the bad block position */
-               this->badblockpos = mtd->oobblock > 512 ? 
+               this->badblockpos = mtd->oobblock > 512 ?
                        NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
  
                /* Get chip options, preserve non chip based options */
                this->options |= NAND_NO_AUTOINCR;
                /* Check if this is a not a samsung device. Do not clear the options
                 * for chips which are not having an extended id.
-                */     
+                */
                if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
                        this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
-               
                /* Check for AND chips with 4 page planes */
                if (this->options & NAND_4PAGE_ARRAY)
                        this->erase_cmd = multi_erase_cmd;
                /* Do not replace user supplied command function ! */
                if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
                        this->cmdfunc = nand_command_lp;
-                               
                printk (KERN_INFO "NAND device: Manufacturer ID:"
-                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
                        nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
                break;
        }
        }
        if (i > 1)
                printk(KERN_INFO "%d NAND chips detected\n", i);
-       
        /* Allocate buffers, if neccecary */
        if (!this->oob_buf) {
                size_t len;
                }
                this->options |= NAND_OOBBUF_ALLOC;
        }
-       
        if (!this->data_buf) {
                size_t len;
                len = mtd->oobblock + mtd->oobsize;
        if (!this->autooob) {
                /* Select the appropriate default oob placement scheme for
                 * placement agnostic filesystems */
-               switch (mtd->oobsize) { 
+               switch (mtd->oobsize) {
                case 8:
                        this->autooob = &nand_oob_8;
                        break;
                        BUG();
                }
        }
-       
        /* The number of bytes available for the filesystem to place fs dependend
         * oob data */
        mtd->oobavail = 0;
        for (i = 0; this->autooob->oobfree[i][1]; i++)
                mtd->oobavail += this->autooob->oobfree[i][1];
  
-       /* 
+       /*
         * check ECC mode, default to software
         * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
-        * fallback to software ECC 
+        * fallback to software ECC
        */
-       this->eccsize = 256;    /* set default eccsize */       
+       this->eccsize = 256;    /* set default eccsize */
        this->eccbytes = 3;
  
        switch (this->eccmode) {
                        this->eccsize = 2048;
                break;
  
-       case NAND_ECC_HW3_512: 
-       case NAND_ECC_HW6_512: 
-       case NAND_ECC_HW8_512: 
+       case NAND_ECC_HW3_512:
+       case NAND_ECC_HW6_512:
+       case NAND_ECC_HW8_512:
                if (mtd->oobblock == 256) {
                        printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
                        this->eccmode = NAND_ECC_SOFT;
                        this->calculate_ecc = nand_calculate_ecc;
                        this->correct_data = nand_correct_data;
-               } else 
+               } else
                        this->eccsize = 512; /* set eccsize to 512 */
                break;
-                       
        case NAND_ECC_HW3_256:
                break;
-               
-       case NAND_ECC_NONE: 
+       case NAND_ECC_NONE:
                printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
                this->eccmode = NAND_ECC_NONE;
                break;
  
-       case NAND_ECC_SOFT:     
+       case NAND_ECC_SOFT:
                this->calculate_ecc = nand_calculate_ecc;
                this->correct_data = nand_correct_data;
                break;
  
        default:
                printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-               BUG();  
-       }       
+               BUG();
+       }
  
-       /* Check hardware ecc function availability and adjust number of ecc bytes per 
+       /* Check hardware ecc function availability and adjust number of ecc bytes per
         * calculation step
        */
        switch (this->eccmode) {
        case NAND_ECC_HW12_2048:
                this->eccbytes += 4;
-       case NAND_ECC_HW8_512: 
+       case NAND_ECC_HW8_512:
                this->eccbytes += 2;
-       case NAND_ECC_HW6_512: 
+       case NAND_ECC_HW6_512:
                this->eccbytes += 3;
-       case NAND_ECC_HW3_512: 
+       case NAND_ECC_HW3_512:
        case NAND_ECC_HW3_256:
                if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
                        break;
                printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
-               BUG();  
+               BUG();
        }
-               
        mtd->eccsize = this->eccsize;
-       
        /* Set the number of read / write steps for one page to ensure ECC generation */
        switch (this->eccmode) {
        case NAND_ECC_HW12_2048:
                this->eccsteps = mtd->oobblock / 512;
                break;
        case NAND_ECC_HW3_256:
-       case NAND_ECC_SOFT:     
+       case NAND_ECC_SOFT:
                this->eccsteps = mtd->oobblock / 256;
                break;
-               
-       case NAND_ECC_NONE: 
+       case NAND_ECC_NONE:
                this->eccsteps = 1;
                break;
        }
-       
        /* Initialize state, waitqueue and spinlock */
        this->state = FL_READY;
        init_waitqueue_head (&this->wq);
        mtd->sync = nand_sync;
        mtd->lock = NULL;
        mtd->unlock = NULL;
-       mtd->suspend = NULL;
-       mtd->resume = NULL;
+       mtd->suspend = nand_suspend;
+       mtd->resume = nand_resume;
        mtd->block_isbad = nand_block_isbad;
        mtd->block_markbad = nand_block_markbad;
  
        memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
  
        mtd->owner = THIS_MODULE;
-       
        /* Check, if we should skip the bad block table scan */
        if (this->options & NAND_SKIP_BBTSCAN)
                return 0;
  }
  
  /**
-  * nand_release - [NAND Interface] Free resources held by the NAND device 
+  * nand_release - [NAND Interface] Free resources held by the NAND device
   * @mtd:      MTD device structure
  */
  void nand_release (struct mtd_info *mtd)
        /* Deregister the device */
        del_mtd_device (mtd);
  
 -      /* Free bad block table memory, if allocated */
 -      if (this->bbt)
 -              kfree (this->bbt);
 +      /* Free bad block table memory */
 +      kfree (this->bbt);
        /* Buffer allocated by nand_scan ? */
        if (this->options & NAND_OOBBUF_ALLOC)
                kfree (this->oob_buf);
diff --combined drivers/mtd/nftlcore.c
index 062ff3877536066e04a56bdd2bac8d0a3b0829ff,89d662999e7ba307ea362a502751774d064b8d68..d7cd5fa16ba445e8d854760de615e7ec15821949
@@@ -1,7 -1,7 +1,7 @@@
  /* Linux driver for NAND Flash Translation Layer      */
  /* (c) 1999 Machine Vision Holdings, Inc.             */
  /* Author: David Woodhouse <dwmw2@infradead.org>      */
- /* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */
+ /* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */
  
  /*
    The contents of this file are distributed under the GNU General
@@@ -101,21 -101,23 +101,21 @@@ static void nftl_add_mtd(struct mtd_blk
  
        if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
                /*
-                 Oh no we don't have 
+                 Oh no we don't have
                   mbd.size == heads * cylinders * sectors
                */
                printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
                       "match size of 0x%lx.\n", nftl->mbd.size);
                printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
                        "(== 0x%lx sects)\n",
-                       nftl->cylinders, nftl->heads , nftl->sectors, 
+                       nftl->cylinders, nftl->heads , nftl->sectors,
                        (long)nftl->cylinders * (long)nftl->heads *
                        (long)nftl->sectors );
        }
  
        if (add_mtd_blktrans_dev(&nftl->mbd)) {
 -              if (nftl->ReplUnitTable)
 -                      kfree(nftl->ReplUnitTable);
 -              if (nftl->EUNtable)
 -                      kfree(nftl->EUNtable);
 +              kfree(nftl->ReplUnitTable);
 +              kfree(nftl->EUNtable);
                kfree(nftl);
                return;
        }
@@@ -131,8 -133,10 +131,8 @@@ static void nftl_remove_dev(struct mtd_
        DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
  
        del_mtd_blktrans_dev(dev);
 -      if (nftl->ReplUnitTable)
 -              kfree(nftl->ReplUnitTable);
 -      if (nftl->EUNtable)
 -              kfree(nftl->EUNtable);
 +      kfree(nftl->ReplUnitTable);
 +      kfree(nftl->EUNtable);
        kfree(nftl);
  }
  
@@@ -174,7 -178,7 +174,7 @@@ static u16 NFTL_findfreeblock(struct NF
  
                if (!silly--) {
                        printk("Argh! No free blocks found! LastFreeEUN = %d, "
-                              "FirstEUN = %d\n", nftl->LastFreeEUN, 
+                              "FirstEUN = %d\n", nftl->LastFreeEUN,
                               le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
                        return 0xffff;
                }
@@@ -206,7 -210,7 +206,7 @@@ static u16 NFTL_foldchain (struct NFTLr
                       "Virtual Unit Chain %d!\n", thisVUC);
                return BLOCK_NIL;
        }
-       
        /* Scan to find the Erase Unit which holds the actual data for each
           512-byte block within the Chain.
        */
                        if (block == 2) {
                                  foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
                                  if (foldmark == FOLD_MARK_IN_PROGRESS) {
-                                         DEBUG(MTD_DEBUG_LEVEL1, 
+                                         DEBUG(MTD_DEBUG_LEVEL1,
                                                "Write Inhibited on EUN %d\n", thisEUN);
                                        inplace = 0;
                                } else {
                                if (!BlockFreeFound[block])
                                        BlockMap[block] = thisEUN;
                                else
-                                       printk(KERN_WARNING 
+                                       printk(KERN_WARNING
                                               "SECTOR_USED found after SECTOR_FREE "
                                               "in Virtual Unit Chain %d for block %d\n",
                                               thisVUC, block);
                                if (!BlockFreeFound[block])
                                        BlockMap[block] = BLOCK_NIL;
                                else
-                                       printk(KERN_WARNING 
+                                       printk(KERN_WARNING
                                               "SECTOR_DELETED found after SECTOR_FREE "
                                               "in Virtual Unit Chain %d for block %d\n",
                                               thisVUC, block);
                               thisVUC);
                        return BLOCK_NIL;
                }
-               
                thisEUN = nftl->ReplUnitTable[thisEUN];
        }
  
        if (inplace) {
                /* We're being asked to be a fold-in-place. Check
                   that all blocks which actually have data associated
-                  with them (i.e. BlockMap[block] != BLOCK_NIL) are 
+                  with them (i.e. BlockMap[block] != BLOCK_NIL) are
                   either already present or SECTOR_FREE in the target
                   block. If not, we're going to have to fold out-of-place
                   anyway.
                                      "block %d was %x lastEUN, "
                                      "and is in EUN %d (%s) %d\n",
                                      thisVUC, block, BlockLastState[block],
-                                     BlockMap[block], 
+                                     BlockMap[block],
                                      BlockMap[block]== targetEUN ? "==" : "!=",
                                      targetEUN);
                                inplace = 0;
                        inplace = 0;
                }
        }
-       
        if (!inplace) {
                DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
                      "Trying out-of-place\n", thisVUC);
                /* We need to find a targetEUN to fold into. */
                targetEUN = NFTL_findfreeblock(nftl, 1);
                if (targetEUN == BLOCK_NIL) {
-                       /* Ouch. Now we're screwed. We need to do a 
+                       /* Ouch. Now we're screwed. We need to do a
                           fold-in-place of another chain to make room
                           for this one. We need a better way of selecting
-                          which chain to fold, because makefreeblock will 
+                          which chain to fold, because makefreeblock will
                           only ask us to fold the same one again.
                        */
                        printk(KERN_WARNING
                 chain by selecting the longer one */
              oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
              oob.u.c.unused = 0xffffffff;
-             MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
+             MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
                           8, &retlen, (char *)&oob.u);
          }
  
                     happen in case of media errors or deleted blocks) */
                  if (BlockMap[block] == BLOCK_NIL)
                          continue;
-                 
                  ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-                                 512, &retlen, movebuf); 
+                                 512, &retlen, movebuf);
                  if (ret < 0) {
                      ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
                                        + (block * 512), 512, &retlen,
-                                       movebuf); 
-                     if (ret != -EIO) 
+                                       movebuf);
+                     if (ret != -EIO)
                          printk("Error went away on retry.\n");
                  }
                memset(&oob, 0xff, sizeof(struct nftl_oob));
                  MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
                               512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
        }
-         
          /* add the header so that it is now a valid chain */
          oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
                  = cpu_to_le16(thisVUC);
          oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
-         
-         MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 
+         MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
                       8, &retlen, (char *)&oob.u);
  
        /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
  
-       /* At this point, we have two different chains for this Virtual Unit, and no way to tell 
+       /* At this point, we have two different chains for this Virtual Unit, and no way to tell
           them apart. If we crash now, we get confused. However, both contain the same data, so we
           shouldn't actually lose data in this case. It's just that when we load up on a medium which
           has duplicate chains, we need to free one of the chains because it's not necessary any more.
        thisEUN = nftl->EUNtable[thisVUC];
        DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
  
-       /* For each block in the old chain (except the targetEUN of course), 
+       /* For each block in the old chain (except the targetEUN of course),
           free it and make it available for future use */
        while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
                unsigned int EUNtmp;
                  }
                  thisEUN = EUNtmp;
        }
-       
        /* Make this the new start of chain for thisVUC */
        nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
        nftl->EUNtable[thisVUC] = targetEUN;
  
  static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
  {
-       /* This is the part that needs some cleverness applied. 
+       /* This is the part that needs some cleverness applied.
           For now, I'm doing the minimum applicable to actually
           get the thing to work.
           Wear-levelling and other clever stuff needs to be implemented
        return NFTL_foldchain (nftl, LongestChain, pendingblock);
  }
  
- /* NFTL_findwriteunit: Return the unit number into which we can write 
+ /* NFTL_findwriteunit: Return the unit number into which we can write
                         for this block. Make it available if it isn't already
  */
  static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                   a free space for the block in question.
                */
  
-               /* This condition catches the 0x[7f]fff cases, as well as 
+               /* This condition catches the 0x[7f]fff cases, as well as
                   being a sanity check for past-end-of-media access
                */
                lastEUN = BLOCK_NIL;
  
                        MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
                                    8, &retlen, (char *)&bci);
-                       
                        DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
                              block , writeEUN, le16_to_cpu(bci.Status));
  
                                break;
                        default:
                                // Invalid block. Don't use it any more. Must implement.
-                               break;                  
+                               break;
                        }
-                       
-                       if (!silly--) { 
+                       if (!silly--) {
                                printk(KERN_WARNING
                                       "Infinite loop in Virtual Unit Chain 0x%x\n",
                                       thisVUC);
                        writeEUN = nftl->ReplUnitTable[writeEUN];
                }
  
-               /* OK. We didn't find one in the existing chain, or there 
+               /* OK. We didn't find one in the existing chain, or there
                   is no existing chain. */
  
                /* Try to find an already-free block */
  
                        /* First remember the start of this chain */
                        //u16 startEUN = nftl->EUNtable[thisVUC];
-                       
                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
                        writeEUN = NFTL_makefreeblock(nftl, 0xffff);
  
                        if (writeEUN == BLOCK_NIL) {
-                               /* OK, we accept that the above comment is 
+                               /* OK, we accept that the above comment is
                                   lying - there may have been free blocks
                                   last time we called NFTL_findfreeblock(),
                                   but they are reserved for when we're
                        }
                        if (writeEUN == BLOCK_NIL) {
                                /* Ouch. This should never happen - we should
-                                  always be able to make some room somehow. 
-                                  If we get here, we've allocated more storage 
+                                  always be able to make some room somehow.
+                                  If we get here, we've allocated more storage
                                   space than actual media, or our makefreeblock
                                   routine is missing something.
                                */
                                printk(KERN_WARNING "Cannot make free space.\n");
                                return BLOCK_NIL;
-                       }                       
+                       }
                        //printk("Restarting scan\n");
                        lastEUN = BLOCK_NIL;
                        continue;
                }
  
                /* We've found a free block. Insert it into the chain. */
-               
                if (lastEUN != BLOCK_NIL) {
                      thisVUC |= 0x8000; /* It's a replacement block */
                } else {
@@@ -745,7 -749,7 +745,7 @@@ extern char nftlmountrev[]
  
  static int __init init_nftl(void)
  {
-       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev);
+       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev);
  
        return register_mtd_blktrans(&nftl_tr);
  }
diff --combined fs/Kconfig
index 7cf36ca157ffed120b4e9a3ec771725964ea245d,660a0c04d6b9ae8c56ff3a20b44552dbf1a451b4..7d6ae369ce4404600489c238908087774bb424d1
@@@ -898,7 -898,6 +898,7 @@@ config AFFS_F
  config HFS_FS
        tristate "Apple Macintosh file system support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
 +      select NLS
        help
          If you say Y here, you will be able to mount Macintosh-formatted
          floppy disks and hard drive partitions with full read-write access.
@@@ -1051,6 -1050,19 +1051,19 @@@ config JFFS2_FS_WRITEBUFFE
            - NOR flash with transparent ECC
            - DataFlash
  
+ config JFFS2_SUMMARY
+       bool "JFFS2 summary support (EXPERIMENTAL)"
+       depends on JFFS2_FS && EXPERIMENTAL
+       default n
+       help
+         This feature makes it possible to use summary information
+         for faster filesystem mount.
+         The summary information can be inserted into a filesystem image
+         by the utility 'sumtool'.
+         If unsure, say 'N'.
  config JFFS2_COMPRESSION_OPTIONS
        bool "Advanced compression options for JFFS2"
        depends on JFFS2_FS
@@@ -1072,10 -1084,10 +1085,10 @@@ config JFFS2_ZLI
        default y
          help
            Zlib is designed to be a free, general-purpose, legally unencumbered,
-           lossless data-compression library for use on virtually any computer 
+           lossless data-compression library for use on virtually any computer
            hardware and operating system. See <http://www.gzip.org/zlib/> for
            further information.
-           
            Say 'Y' if unsure.
  
  config JFFS2_RTIME
@@@ -1097,7 -1109,7 +1110,7 @@@ choic
          default JFFS2_CMODE_PRIORITY
          depends on JFFS2_FS
          help
-           You can set here the default compression mode of JFFS2 from 
+           You can set here the default compression mode of JFFS2 from
            the available compression modes. Don't touch if unsure.
  
  config JFFS2_CMODE_NONE
  config JFFS2_CMODE_PRIORITY
          bool "priority"
          help
-           Tries the compressors in a predefinied order and chooses the first 
+           Tries the compressors in a predefinied order and chooses the first
            successful one.
  
  config JFFS2_CMODE_SIZE
          bool "size (EXPERIMENTAL)"
          help
-           Tries all compressors and chooses the one which has the smallest 
+           Tries all compressors and chooses the one which has the smallest
            result.
  
  endchoice
diff --combined fs/jffs2/wbuf.c
index 7bc7f2d571f68f9bca429d23a41e0754ad9274f9,242cd53a970c5bf96f561d4752813cb66295de21..4cebf0e57c465bbf130b7077ea667ded3bac0b08
@@@ -9,7 -9,7 +9,7 @@@
   *
   * For licensing information, see the file 'LICENCE' in this directory.
   *
-  * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $
+  * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $
   *
   */
  
  static unsigned char *brokenbuf;
  #endif
  
+ #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
+ #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
  /* max. erase failures before we mark a block bad */
  #define MAX_ERASE_FAILURES    2
  
- /* two seconds timeout for timed wbuf-flushing */
- #define WBUF_FLUSH_TIMEOUT    2 * HZ
  struct jffs2_inodirty {
        uint32_t ino;
        struct jffs2_inodirty *next;
@@@ -139,7 -139,6 +139,6 @@@ static void jffs2_block_refile(struct j
  {
        D1(printk("About to refile bad block at %08x\n", jeb->offset));
  
-       D2(jffs2_dump_block_lists(c));
        /* File the existing block on the bad_used_list.... */
        if (c->nextblock == jeb)
                c->nextblock = NULL;
                c->nr_erasing_blocks++;
                jffs2_erase_pending_trigger(c);
        }
-       D2(jffs2_dump_block_lists(c));
  
        /* Adjust its size counts accordingly */
        c->wasted_size += jeb->free_size;
        jeb->wasted_size += jeb->free_size;
        jeb->free_size = 0;
  
-       ACCT_SANITY_CHECK(c,jeb);
-       D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_dump_block_lists_nolock(c);
+       jffs2_dbg_acct_sanity_check_nolock(c,jeb);
+       jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
  }
  
  /* Recover from failure to write wbuf. Recover the nodes up to the
@@@ -189,7 -188,7 +188,7 @@@ static void jffs2_wbuf_recover(struct j
        /* Find the first node to be recovered, by skipping over every
           node which ends before the wbuf starts, or which is obsolete. */
        first_raw = &jeb->first_node;
-       while (*first_raw && 
+       while (*first_raw &&
               (ref_obsolete(*first_raw) ||
                (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) {
                D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
                        ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
                else
                        ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
-               
                if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
                        /* ECC recovered */
                        ret = 0;
  
  
        /* ... and get an allocation of space from a shiny new block instead */
-       ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
+       ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE);
        if (ret) {
                printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
                kfree(buf);
        if (end-start >= c->wbuf_pagesize) {
                /* Need to do another write immediately, but it's possible
                   that this is just because the wbuf itself is completely
-                  full, and there's nothing earlier read back from the 
-                  flash. Hence 'buf' isn't necessarily what we're writing 
+                  full, and there's nothing earlier read back from the
+                  flash. Hence 'buf' isn't necessarily what we're writing
                   from. */
                unsigned char *rewrite_buf = buf?:c->wbuf;
                uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
  
                D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
                          towrite, ofs));
-         
  #ifdef BREAKMEHEADER
                static int breakme;
                if (breakme++ == 20) {
                c->wbuf_ofs = ofs + towrite;
                memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
                /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
 -              if (buf)
 -                      kfree(buf);
 +              kfree(buf);
        } else {
                /* OK, now we're left with the dregs in whichever buffer we're using */
                if (buf) {
        else
                jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
  
-       ACCT_SANITY_CHECK(c,jeb);
-         D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c, jeb);
+         jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
  
-       ACCT_SANITY_CHECK(c,new_jeb);
-         D1(ACCT_PARANOIA_CHECK(new_jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c, new_jeb);
+         jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb);
  
        spin_unlock(&c->erase_completion_lock);
  
@@@ -434,15 -434,15 +433,15 @@@ static int __jffs2_flush_wbuf(struct jf
           this happens, if we have a change to a new block,
           or if fsync forces us to flush the writebuffer.
           if we have a switch to next page, we will not have
-          enough remaining space for this. 
+          enough remaining space for this.
        */
-       if (pad && !jffs2_dataflash(c)) {
+       if (pad ) {
                c->wbuf_len = PAD(c->wbuf_len);
  
                /* Pad with JFFS2_DIRTY_BITMASK initially.  this helps out ECC'd NOR
                   with 8 byte page size */
                memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
-               
                if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
                        struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
                        padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        }
        /* else jffs2_flash_writev has actually filled in the rest of the
           buffer for us, and will deal with the node refs etc. later. */
-       
  #ifdef BREAKME
        static int breakme;
        if (breakme++ == 20) {
                c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
                                        &retlen, brokenbuf, NULL, c->oobinfo);
                ret = -EIO;
-       } else 
+       } else
  #endif
-       
        if (jffs2_cleanmarker_oob(c))
                ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
        else
        spin_lock(&c->erase_completion_lock);
  
        /* Adjust free size of the block if we padded. */
-       if (pad && !jffs2_dataflash(c)) {
+       if (pad) {
                struct jffs2_eraseblock *jeb;
  
                jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
                D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
                          (jeb==c->nextblock)?"next":"", jeb->offset));
  
-               /* wbuf_pagesize - wbuf_len is the amount of space that's to be 
+               /* wbuf_pagesize - wbuf_len is the amount of space that's to be
                   padded. If there is less free space in the block than that,
                   something screwed up */
                if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
        return 0;
  }
  
- /* Trigger garbage collection to flush the write-buffer. 
+ /* Trigger garbage collection to flush the write-buffer.
     If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
-    outstanding. If ino arg non-zero, do it only if a write for the 
+    outstanding. If ino arg non-zero, do it only if a write for the
     given inode is outstanding. */
  int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
  {
@@@ -604,15 -604,6 +603,6 @@@ int jffs2_flush_wbuf_pad(struct jffs2_s
  
        return ret;
  }
- #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
- #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
- #else
- #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
- #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
- #endif
  int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
  {
        struct kvec outvecs[3];
        /* If not NAND flash, don't bother */
        if (!jffs2_is_writebuffered(c))
                return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
-       
        down_write(&c->wbuf_sem);
  
        /* If wbuf_ofs is not initialized, set it to target address */
        if (c->wbuf_ofs == 0xFFFFFFFF) {
                c->wbuf_ofs = PAGE_DIV(to);
-               c->wbuf_len = PAGE_MOD(to);                     
+               c->wbuf_len = PAGE_MOD(to);
                memset(c->wbuf,0xff,c->wbuf_pagesize);
        }
  
                        memset(c->wbuf,0xff,c->wbuf_pagesize);
                }
        }
-       
-       /* Sanity checks on target address. 
-          It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), 
-          and it's permitted to write at the beginning of a new 
+       /* Sanity checks on target address.
+          It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs),
+          and it's permitted to write at the beginning of a new
           erase block. Anything else, and you die.
           New block starts at xxx000c (0-b = block header)
        */
                }
                /* set pointer to new block */
                c->wbuf_ofs = PAGE_DIV(to);
-               c->wbuf_len = PAGE_MOD(to);                     
-       } 
+               c->wbuf_len = PAGE_MOD(to);
+       }
  
        if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
                /* We're not writing immediately after the writebuffer. Bad. */
        invec = 0;
        outvec = 0;
  
-       /* Fill writebuffer first, if already in use */ 
+       /* Fill writebuffer first, if already in use */
        if (c->wbuf_len) {
                uint32_t invec_ofs = 0;
  
-               /* adjust alignment offset */ 
+               /* adjust alignment offset */
                if (c->wbuf_len != PAGE_MOD(to)) {
                        c->wbuf_len = PAGE_MOD(to);
                        /* take care of alignment to next page */
                        if (!c->wbuf_len)
                                c->wbuf_len = c->wbuf_pagesize;
                }
-               
                while(c->wbuf_len < c->wbuf_pagesize) {
                        uint32_t thislen;
-                       
                        if (invec == count)
                                goto alldone;
  
  
                        if (thislen >= invecs[invec].iov_len)
                                thislen = invecs[invec].iov_len;
-       
                        invec_ofs = thislen;
  
                        memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
                        c->wbuf_len += thislen;
                        donelen += thislen;
                        /* Get next invec, if actual did not fill the buffer */
-                       if (c->wbuf_len < c->wbuf_pagesize) 
+                       if (c->wbuf_len < c->wbuf_pagesize)
                                invec++;
-               }                       
-               
+               }
                /* write buffer is full, flush buffer */
                ret = __jffs2_flush_wbuf(c, NOPAD);
                if (ret) {
  
                /* We did cross a page boundary, so we write some now */
                if (jffs2_cleanmarker_oob(c))
-                       ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 
+                       ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
                else
                        ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
-               
                if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
                        /* At this point we have no problem,
                           c->wbuf is empty. However refile nextblock to avoid
                        spin_unlock(&c->erase_completion_lock);
                        goto exit;
                }
-               
                donelen += wbuf_retlen;
                c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);
  
  alldone:
        *retlen = donelen;
  
+       if (jffs2_sum_active()) {
+               int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
+               if (res)
+                       return res;
+       }
        if (c->wbuf_len && ino)
                jffs2_wbuf_dirties_inode(c, ino);
  
        ret = 0;
-       
  exit:
        up_write(&c->wbuf_sem);
        return ret;
@@@ -855,7 -852,7 +851,7 @@@ int jffs2_flash_write(struct jffs2_sb_i
        struct kvec vecs[1];
  
        if (!jffs2_is_writebuffered(c))
-               return c->mtd->write(c->mtd, ofs, len, retlen, buf);
+               return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
  
        vecs[0].iov_base = (unsigned char *) buf;
        vecs[0].iov_len = len;
@@@ -883,18 -880,18 +879,18 @@@ int jffs2_flash_read(struct jffs2_sb_in
        if ( (ret == -EBADMSG) && (*retlen == len) ) {
                printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
                       len, ofs);
-               /* 
-                * We have the raw data without ECC correction in the buffer, maybe 
+               /*
+                * We have the raw data without ECC correction in the buffer, maybe
                 * we are lucky and all data or parts are correct. We check the node.
                 * If data are corrupted node check will sort it out.
                 * We keep this block, it will fail on write or erase and the we
                 * mark it bad. Or should we do that now? But we should give him a chance.
-                * Maybe we had a system crash or power loss before the ecc write or  
+                * Maybe we had a system crash or power loss before the ecc write or
                 * a erase was completed.
                 * So we return success. :)
                 */
                ret = 0;
-       }       
+       }
  
        /* if no writebuffer available or write buffer empty, return */
        if (!c->wbuf_pagesize || !c->wbuf_len)
                if (owbf > c->wbuf_len)         /* is read beyond write buffer ? */
                        goto exit;
                lwbf = c->wbuf_len - owbf;      /* number of bytes to copy */
-               if (lwbf > len) 
+               if (lwbf > len)
                        lwbf = len;
-       } else {        
+       } else {
                orbf = (c->wbuf_ofs - ofs);     /* offset in read buffer */
                if (orbf > len)                 /* is write beyond write buffer ? */
                        goto exit;
                lwbf = len - orbf;              /* number of bytes to copy */
-               if (lwbf > c->wbuf_len) 
+               if (lwbf > c->wbuf_len)
                        lwbf = c->wbuf_len;
-       }       
+       }
        if (lwbf > 0)
                memcpy(buf+orbf,c->wbuf+owbf,lwbf);
  
@@@ -946,7 -943,7 +942,7 @@@ int jffs2_check_oob_empty( struct jffs2
                printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n");
                return -ENOMEM;
        }
-       /* 
+       /*
         * if mode = 0, we scan for a total empty oob area, else we have
         * to take care of the cleanmarker in the first page of the block
        */
                D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
                goto out;
        }
-       
        if (retlen < len) {
                D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read "
                          "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
                ret = -EIO;
                goto out;
        }
-       
        /* Special check for first page */
        for(i = 0; i < oob_size ; i++) {
                /* Yeah, we know about the cleanmarker. */
-               if (mode && i >= c->fsdata_pos && 
+               if (mode && i >= c->fsdata_pos &&
                    i < c->fsdata_pos + c->fsdata_len)
                        continue;
  
                if (buf[i] != 0xFF) {
                        D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
-                                 buf[page+i], page+i, jeb->offset));
-                       ret = 1; 
+                                 buf[i], i, jeb->offset));
+                       ret = 1;
                        goto out;
                }
        }
  
-       /* we know, we are aligned :) */        
+       /* we know, we are aligned :) */
        for (page = oob_size; page < len; page += sizeof(long)) {
                unsigned long dat = *(unsigned long *)(&buf[page]);
                if(dat != -1) {
-                       ret = 1; 
+                       ret = 1;
                        goto out;
                }
        }
  
  out:
-       kfree(buf);     
-       
+       kfree(buf);
        return ret;
  }
  
@@@ -1071,7 -1068,7 +1067,7 @@@ int jffs2_write_nand_cleanmarker(struc
        n.totlen = cpu_to_je32(8);
  
        ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
-       
        if (ret) {
                D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
                return ret;
        return 0;
  }
  
- /* 
+ /*
   * On NAND we try to mark this block bad. If the block was erased more
   * than MAX_ERASE_FAILURES we mark it finaly bad.
   * Don't care about failures. This block remains on the erase-pending
@@@ -1104,7 -1101,7 +1100,7 @@@ int jffs2_write_nand_badblock(struct jf
  
        D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset));
        ret = c->mtd->block_markbad(c->mtd, bad_offset);
-       
        if (ret) {
                D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
                return ret;
@@@ -1128,7 -1125,7 +1124,7 @@@ static int jffs2_nand_set_oobinfo(struc
        /* Do this only, if we have an oob buffer */
        if (!c->mtd->oobsize)
                return 0;
-       
        /* Cleanmarker is out-of-band, so inline size zero */
        c->cleanmarker_size = 0;
  
                        c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
                        c->badblock_pos = 15;
                        break;
-       
                default:
                        D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
                        return -EINVAL;
@@@ -1171,7 -1168,7 +1167,7 @@@ int jffs2_nand_flash_setup(struct jffs2
        init_rwsem(&c->wbuf_sem);
        c->wbuf_pagesize = c->mtd->oobblock;
        c->wbuf_ofs = 0xFFFFFFFF;
-       
        c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
        if (!c->wbuf)
                return -ENOMEM;
@@@ -1197,17 -1194,41 +1193,41 @@@ void jffs2_nand_flash_cleanup(struct jf
  
  int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
        c->cleanmarker_size = 0;                /* No cleanmarkers needed */
-       
        /* Initialize write buffer */
        init_rwsem(&c->wbuf_sem);
-       c->wbuf_pagesize = c->sector_size;
-       c->wbuf_ofs = 0xFFFFFFFF;
  
+       c->wbuf_pagesize =  c->mtd->erasesize;
+       /* Find a suitable c->sector_size
+        * - Not too much sectors
+        * - Sectors have to be at least 4 K + some bytes
+        * - All known dataflashes have erase sizes of 528 or 1056
+        * - we take at least 8 eraseblocks and want to have at least 8K size
+        * - The concatenation should be a power of 2
+       */
+       c->sector_size = 8 * c->mtd->erasesize;
+       while (c->sector_size < 8192) {
+               c->sector_size *= 2;
+       }
+       /* It may be necessary to adjust the flash size */
+       c->flash_size = c->mtd->size;
+       if ((c->flash_size % c->sector_size) != 0) {
+               c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;
+               printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size);
+       };
+       c->wbuf_ofs = 0xFFFFFFFF;
        c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
        if (!c->wbuf)
                return -ENOMEM;
  
-       printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
+       printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
  
        return 0;
  }
@@@ -1235,3 -1256,23 +1255,23 @@@ int jffs2_nor_ecc_flash_setup(struct jf
  void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
        kfree(c->wbuf);
  }
+ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
+       /* Cleanmarker currently occupies a whole programming region */
+       c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd);
+       /* Initialize write buffer */
+       init_rwsem(&c->wbuf_sem);
+       c->wbuf_pagesize = MTD_PROGREGION_SIZE(c->mtd);
+       c->wbuf_ofs = 0xFFFFFFFF;
+       c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+       if (!c->wbuf)
+               return -ENOMEM;
+       return 0;
+ }
+ void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {
+       kfree(c->wbuf);
+ }