changeset 1741:9464c6747e99

Sort out the various loops to cope with boundary conditions, especially flash devices mapped right at the top of memory.
author bartv
date Sat, 20 Nov 2004 19:27:26 +0000
parents 699be933fd5e
children a668b95e5f2e
files packages/io/flash/current/ChangeLog packages/io/flash/current/src/flash.c
diffstat 2 files changed, 227 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/packages/io/flash/current/ChangeLog
+++ b/packages/io/flash/current/ChangeLog
@@ -1,3 +1,8 @@
+2004-11-20  Bart Veer  <bartv@ecoscentric.com>
+
+	* src/flash.c: rearrange loops to avoid address comparisons, which
+	tend to go wrong if the flash is at the end of the address space
+
 2004-10-06  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/legacy_dev.c (legacy_flash_init): The end is the size plus
--- a/packages/io/flash/current/src/flash.c
+++ b/packages/io/flash/current/src/flash.c
@@ -8,9 +8,10 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2004 eCosCentric Ltd.
 // Copyright (C) 2003 Gary Thomas
-// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 //
 // eCos 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
@@ -74,9 +75,6 @@
 #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
 # warning "Can only enable the flash debugging when configured for RAM startup"
 #endif
-#ifndef MIN
-#define MIN(x,y) ((x)<(y) ? (x) : (y))
-#endif
 
 // Has the FLASH IO library been initialise?
 static bool init = false;
@@ -202,7 +200,7 @@ cyg_flash_verify_addr(const cyg_flashadd
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
   
   for (dev = flash_head; dev; dev=dev->next) {
-    if ((dev->start <= address) && (dev->end > address))
+    if ((dev->start <= address) && (address <= dev->end))
       return CYG_FLASH_ERR_OK;
   }
   return CYG_FLASH_ERR_INVALID;
@@ -249,7 +247,7 @@ cyg_flash_get_info_addr(cyg_flashaddr_t 
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
   
   for (dev = flash_head; dev ; dev=dev->next) {
-    if ((dev->start <= flash_base) && ( dev->end > flash_base)) {
+    if ((dev->start <= flash_base) && ( flash_base <= dev->end)) {
     info->start = dev->start;
     info->end = dev->end;
     info->num_block_infos = dev->num_block_infos;
@@ -271,7 +269,7 @@ cyg_flash_mutex_lock(const cyg_flashaddr
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
   
   for (dev = flash_head; dev ; dev=dev->next) {
-    if ((dev->start <= from) && ( dev->end > from)) {
+    if ((dev->start <= from) && ( from <= dev->end)) {
       cyg_mutex_lock(&dev->mutex);
       if (dev->end > from+len) {
         return CYG_FLASH_ERR_OK;
@@ -299,7 +297,7 @@ cyg_flash_mutex_unlock(const cyg_flashad
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
   
   for (dev = flash_head; dev ; dev=dev->next) {
-    if ((dev->start <= from) && ( dev->end > from)) {
+    if ((dev->start <= from) && ( from <= dev->end)) {
       cyg_mutex_unlock(&dev->mutex);
       if (dev->end > from+len) {
         return CYG_FLASH_ERR_OK;
@@ -344,7 +342,7 @@ cyg_flash_block_size(const cyg_flashaddr
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
 
   for (dev = flash_head; 
-       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev && !((dev->start <= flash_base) && ( flash_base <= dev->end));
        dev=dev->next)
     ;
   if (!dev) return CYG_FLASH_ERR_INVALID;
@@ -374,21 +372,21 @@ cyg_flash_erase(const cyg_flashaddr_t fl
                 const size_t len, 
                 cyg_flashaddr_t *err_address)
 {
-  cyg_flashaddr_t block, end_addr, addr;
+  cyg_flashaddr_t block, end_addr;
   struct cyg_flash_dev * dev;
-  size_t block_size;
+  size_t erase_count;
   int stat = CYG_FLASH_ERR_OK;
   int d_cache, i_cache;
   
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
   
 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-  if (plf_flash_query_soft_wp(addr,len))
+  if (plf_flash_query_soft_wp(flash_base,len))
     return CYG_FLASH_ERR_PROTECT;
 #endif
   
   for (dev = flash_head; 
-       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev && !((dev->start <= flash_base) && ( flash_base <= dev->end));
        dev=dev->next)
     ;
   if (!dev) return CYG_FLASH_ERR_INVALID;
@@ -396,30 +394,40 @@ cyg_flash_erase(const cyg_flashaddr_t fl
 #ifdef CYGPKG_KERNEL
   cyg_mutex_lock(&dev->mutex);
 #endif
-  addr = flash_base;
-  end_addr = flash_base + len - 1;
-  if (end_addr > dev->end) {
-    end_addr = dev->end;
+
+  // Check whether or not we are going past the end of this device, on
+  // to the next one. If so the next device will be handled by a
+  // recursive call later on.
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
   }
-  
-  block = flash_block_begin(addr, dev);
-  
+  // erase can only happen on a block boundary, so adjust for this
+  block         = flash_block_begin(flash_base, dev);
+  erase_count   = (end_addr + 1) - block;
+
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("... Erase from %p-%p: ", (void*)block, (void*)end_addr);
 #endif
   
   HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-  FLASH_Enable(block, end_addr);
-  while (block <= end_addr) {
+  FLASH_Enable(flash_base, end_addr);
+  while (erase_count > 0) {
     int i;
     unsigned char *dp;
-    bool erased = true;
+    bool erased = false;
+    size_t block_size = flash_block_size(dev, block);
 
-    block_size = flash_block_size(dev, addr);
+    // Pad to the block boundary, if necessary
+    if (erase_count < block_size) {
+        erase_count = block_size;
+    }
 
     // If there is a read function it probably means the flash
     // cannot be read directly.
     if (!dev->funs->flash_read) {
+      erased = true;
       dp = (unsigned char *)block;
       for (i = 0;  i < block_size;  i++) {
         if (*dp++ != (unsigned char)0xFF) {
@@ -427,8 +435,6 @@ cyg_flash_erase(const cyg_flashaddr_t fl
           break;
         }
       }
-    } else {
-      erased=false;
     }
     if (!erased) {
       stat = dev->funs->flash_erase_block(dev,block);
@@ -438,12 +444,13 @@ cyg_flash_erase(const cyg_flashaddr_t fl
       *err_address = block;
       break;
     }
-    block += block_size;
+    block       += block_size;
+    erase_count -= block_size;
 #ifdef CYGSEM_IO_FLASH_CHATTER
     dev->pf(".");
 #endif
   }
-  FLASH_Disable(block, end_addr);
+  FLASH_Disable(flash_base, end_addr);
   HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("\n");
@@ -454,11 +461,14 @@ cyg_flash_erase(const cyg_flashaddr_t fl
   if (stat != CYG_FLASH_ERR_OK) {
     return stat;
   }
-  
-  if (flash_base + len - 1 > dev->end) {        
-    // The region to erase if bigger than this driver handles. Recurse
+
+  // If there are multiple flash devices in series the erase operation
+  // may touch successive devices. This can be handled by recursion.
+  // The stack overheads should be minimal because the number of
+  // devices will be small.
+  if (len > (dev->end + 1 - flash_base)) {
     return cyg_flash_erase(dev->end+1, 
-                           len - (dev->end - flash_base) - 1,
+                           len - (dev->end + 1 - flash_base),
                            err_address);
   }
   return CYG_FLASH_ERR_OK;
@@ -471,9 +481,9 @@ cyg_flash_program(const cyg_flashaddr_t 
                   cyg_flashaddr_t *err_address)
 {
   struct cyg_flash_dev * dev;
-  cyg_flashaddr_t addr, end_addr;
+  cyg_flashaddr_t addr, end_addr, block;
   unsigned char * ram = ram_base;
-  size_t block_size, size, length, offset;
+  size_t write_count, offset;
   int stat = CYG_FLASH_ERR_OK;
   int d_cache, i_cache;
   
@@ -485,7 +495,7 @@ cyg_flash_program(const cyg_flashaddr_t 
 #endif
   
   for (dev = flash_head; 
-       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev && !((dev->start <= flash_base) && ( flash_base <= dev->end));
        dev=dev->next)
     ;
   if (!dev) return CYG_FLASH_ERR_INVALID;
@@ -494,34 +504,45 @@ cyg_flash_program(const cyg_flashaddr_t 
   cyg_mutex_lock(&dev->mutex);
 #endif
   addr = flash_base;
-  end_addr = flash_base + len - 1;
-  if (end_addr > dev->end) {
+  if (len > (dev->end + 1 - flash_base)) {
     end_addr = dev->end;
+  } else {
+    end_addr = flash_base + len - 1;
   }
-  length = end_addr - addr + 1;
+  write_count = (end_addr + 1) - flash_base;
+
+  // The first write may be in the middle of a block. Do the necessary
+  // adjustment here rather than inside the loop.
+  block = flash_block_begin(flash_base, dev);
+  if (addr == block) {
+      offset = 0;
+  } else {
+      offset = addr - block;
+  }
   
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("... Program from %p-%p to %p: ", ram_base, 
-          ((CYG_ADDRESS)ram_base)+length, addr);
+          ((CYG_ADDRESS)ram_base)+write_count, addr);
 #endif
   
   HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-  FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
-  while (addr <= end_addr) {
-    block_size = flash_block_size(dev, addr);
-    size = length;
-    // Only one block at once
-    if (size > block_size) size = block_size;
+  FLASH_Enable(flash_base, end_addr);
+  while (write_count > 0) {
+    size_t block_size = flash_block_size(dev, addr);
+    size_t this_write;
+    if (write_count > (block_size - offset)) {
+        this_write = block_size - offset;
+    } else {
+        this_write = write_count;
+    }
+    // Only the first block may need the offset.
+    offset       = 0;
     
-    // Writing from the middle of a block?
-    offset = (size_t)(addr - dev->start) % block_size;
-    if (offset)
-      size = MIN(block_size - offset, size);
-    stat = dev->funs->flash_program(dev, addr, ram, size);
+    stat = dev->funs->flash_program(dev, addr, ram, this_write);
     stat = dev->funs->flash_hwr_map_error(dev,stat);
 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
     if (CYG_FLASH_ERR_OK == stat) // Claims to be OK
-      if (!dev->funs->flash_read && memcmp((void *)addr, ram, size) != 0) {                
+      if (!dev->funs->flash_read && memcmp((void *)addr, ram, this_write) != 0) {                
         stat = CYG_FLASH_ERR_DRV_VERIFY;
 #ifdef CYGSEM_IO_FLASH_CHATTER
         dev->pf("V");
@@ -535,11 +556,11 @@ cyg_flash_program(const cyg_flashaddr_t 
 #ifdef CYGSEM_IO_FLASH_CHATTER
     dev->pf(".");
 #endif
-    length -= size;
-    addr += size;
-    ram += size;
+    write_count -= this_write;
+    addr        += this_write;
+    ram         += this_write;
   }
-  FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
+  FLASH_Disable(flash_base, end_addr);
   HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
     dev->pf("\n");
@@ -550,9 +571,9 @@ cyg_flash_program(const cyg_flashaddr_t 
   if (stat != CYG_FLASH_ERR_OK) {
     return (stat);
   }
-  if ( flash_base + len - 1 > dev->end) {
+  if (len > (dev->end + 1 - flash_base)) {
     return cyg_flash_program(dev->end+1, ram, 
-                             len - (dev->end - flash_base) - 1,
+                             len - (dev->end + 1 - flash_base),
                              err_address);
   }
   return CYG_FLASH_ERR_OK;
@@ -565,16 +586,16 @@ cyg_flash_read(cyg_flashaddr_t flash_bas
                cyg_flashaddr_t *err_address)
 {
   struct cyg_flash_dev * dev;
-  cyg_flashaddr_t addr, end_addr;
+  cyg_flashaddr_t addr, end_addr, block;
   unsigned char * ram = (unsigned char *)ram_base;
-  size_t block_size, size, length, offset;
+  size_t read_count, offset;
   int stat = CYG_FLASH_ERR_OK;
   int d_cache, i_cache;
   
   if (!init) return CYG_FLASH_ERR_NOT_INIT;
   
   for (dev = flash_head; 
-       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev && !((dev->start <= flash_base) && ( flash_base <= dev->end));
        dev=dev->next)
     ;
   if (!dev) return CYG_FLASH_ERR_INVALID;
@@ -583,33 +604,44 @@ cyg_flash_read(cyg_flashaddr_t flash_bas
   cyg_mutex_lock(&dev->mutex);
 #endif
   addr = flash_base;
-  end_addr = flash_base + len - 1;
-  if (end_addr > dev->end) {
-    end_addr = dev->end;
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
   }
-  length = end_addr - addr + 1;
+  read_count = (end_addr + 1) - flash_base;
+
+  // The first read may be in the middle of a block. Do the necessary
+  // adjustment here rather than inside the loop.
+  block = flash_block_begin(flash_base, dev);
+  if (addr == block) {
+      offset = 0;
+  } else {
+      offset = addr - block;
+  }
   
 #ifdef CYGSEM_IO_FLASH_CHATTER
-  dev->pf("... Read from %p-%p to %p: ", addr, addr+len, ram_base);
+  dev->pf("... Read from %p-%p to %p: ", addr, end_addr, ram_base);
 #endif
   
   HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-  FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
-  while (addr <= end_addr) {
-    block_size = flash_block_size(dev, addr);
-    size = length;
-    // Only one block at once
-    if (size > block_size) size = block_size;
+  FLASH_Enable(flash_base, end_addr);
+  while (read_count > 0) {
+    size_t block_size = flash_block_size(dev, addr);
+    size_t this_read;
+    if (read_count > (block_size - offset)) {
+        this_read = block_size - offset;
+    } else {
+        this_read = read_count;
+    }
+    // Only the first block may need the offset
+    offset      = 0;
     
-    // Reading from the middle of a block?
-    offset = (size_t)(addr - dev->start) % block_size;
-    if (offset)
-      size = MIN(block_size - offset, size);
     if (dev->funs->flash_read) {
-      stat = dev->funs->flash_read(dev, addr, ram, size);
+      stat = dev->funs->flash_read(dev, addr, ram, this_read);
       stat = dev->funs->flash_hwr_map_error(dev,stat);
     } else {
-      memcpy(ram, (void *)addr, size);
+      memcpy(ram, (void *)addr, this_read);
       stat = CYG_FLASH_ERR_OK;
     }
     if (CYG_FLASH_ERR_OK != stat && err_address) {
@@ -619,11 +651,11 @@ cyg_flash_read(cyg_flashaddr_t flash_bas
 #ifdef CYGSEM_IO_FLASH_CHATTER
     dev->pf(".");
 #endif
-    length -= size;
-    addr += size;
-    ram += size;
+    read_count  -= this_read;
+    addr        += this_read;
+    ram         += this_read;
   }
-  FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
+  FLASH_Disable(flash_base, end_addr);
   HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("\n");
@@ -634,10 +666,10 @@ cyg_flash_read(cyg_flashaddr_t flash_bas
   if (stat != CYG_FLASH_ERR_OK) {
     return (stat);
   }
-  if ( flash_base + len - 1 > dev->end) {
-    return cyg_flash_read(dev->end+1, ram,
-                          len - (dev->end - flash_base) - 1,
-                          err_address);
+  if (len > (dev->end + 1 - flash_base)) {
+      return cyg_flash_read(dev->end+1, ram,
+                            len - (dev->end + 1 - flash_base),
+                            err_address);
   }
   return CYG_FLASH_ERR_OK;
 }
@@ -648,9 +680,9 @@ cyg_flash_lock(const cyg_flashaddr_t fla
                const size_t len, 
                cyg_flashaddr_t *err_address)
 {
-  cyg_flashaddr_t block, end_addr, addr;
+  cyg_flashaddr_t block, end_addr;
   struct cyg_flash_dev * dev;
-  size_t block_size;
+  size_t lock_count;
   int stat = CYG_FLASH_ERR_OK;
   int d_cache, i_cache;
   
@@ -662,7 +694,7 @@ cyg_flash_lock(const cyg_flashaddr_t fla
 #endif
   
   for (dev = flash_head; 
-       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev && !((dev->start <= flash_base) && ( flash_base <= dev->end));
        dev=dev->next)
     ;
   if (!dev) return CYG_FLASH_ERR_INVALID;
@@ -671,21 +703,25 @@ cyg_flash_lock(const cyg_flashaddr_t fla
 #ifdef CYGPKG_KERNEL
   cyg_mutex_lock(&dev->mutex);
 #endif
-  addr = flash_base;
-  end_addr = flash_base + len - 1;
-  if (end_addr > dev->end) {
-    end_addr = dev->end;
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
   }
-  
-  block = flash_block_begin(addr, dev);
+  block         = flash_block_begin(flash_base, dev);
+  lock_count    = (end_addr + 1) - block;
   
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("... Locking from %p-%p: ", (void*)block, (void*)end_addr);
 #endif
   
   HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-  FLASH_Enable(block, end_addr);
-  while (block <= end_addr) {
+  FLASH_Enable(flash_base, end_addr);
+  while (lock_count > 0) {
+    size_t  block_size  = flash_block_size(dev, block);
+    if (lock_count < block_size) {
+        lock_count = block_size;
+    }
     stat = dev->funs->flash_block_lock(dev,block);
     stat = dev->funs->flash_hwr_map_error(dev,stat);
     
@@ -693,12 +729,96 @@ cyg_flash_lock(const cyg_flashaddr_t fla
       *err_address = block;
       break;
     }
-    block += flash_block_size(dev, addr);
+    block       += block_size;
+    lock_count  -= block_size;
 #ifdef CYGSEM_IO_FLASH_CHATTER
     dev->pf(".");
 #endif
   }
-  FLASH_Disable(block, end_addr);
+  FLASH_Disable(flash_base, end_addr);
+  HAL_FLASH_CACHES_ON(d_cache, i_cache);
+#ifdef CYGSEM_IO_FLASH_CHATTER
+  dev->pf("\n");
+#endif
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_unlock(&dev->mutex);
+#endif
+  if (stat != CYG_FLASH_ERR_OK) {
+    return stat;
+  }
+
+  // Recurse if necessary for the next device
+  if (len > (dev->end + 1 - flash_base)) {
+    return cyg_flash_lock(dev->end+1, 
+                          len - (dev->end + 1 - flash_base),
+                          err_address);
+  }
+
+  return CYG_FLASH_ERR_OK;
+}
+
+__externC int 
+cyg_flash_unlock(const cyg_flashaddr_t flash_base, 
+                 const size_t len, 
+                 cyg_flashaddr_t *err_address)
+{
+  cyg_flashaddr_t block, end_addr;
+  struct cyg_flash_dev * dev;
+  size_t unlock_count;
+  int stat = CYG_FLASH_ERR_OK;
+  int d_cache, i_cache;
+  
+  if (!init) return CYG_FLASH_ERR_NOT_INIT;
+  
+#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
+  if (plf_flash_query_soft_wp(addr,len))
+    return CYG_FLASH_ERR_PROTECT;
+#endif
+  
+  for (dev = flash_head; 
+       dev && !((dev->start <= flash_base) && ( flash_base <= dev->end));
+       dev=dev->next)
+    ;
+  if (!dev) return CYG_FLASH_ERR_INVALID;
+  if (!dev->funs->flash_block_unlock) return CYG_FLASH_ERR_INVALID;
+  
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_lock(&dev->mutex);
+#endif
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
+  }
+  block         = flash_block_begin(flash_base, dev);
+  unlock_count  = (end_addr + 1) - block;
+  
+#ifdef CYGSEM_IO_FLASH_CHATTER
+  dev->pf("... Unlocking from %p-%p: ", (void*)block, (void*)end_addr);
+#endif
+  
+  HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+  FLASH_Enable(flash_base, end_addr);
+  while (unlock_count > 0) {
+    size_t    block_size  = flash_block_size(dev, block);
+    if (unlock_count < block_size) {
+        unlock_count = block_size;
+    }
+    stat = dev->funs->flash_block_unlock(dev,block);
+    stat = dev->funs->flash_hwr_map_error(dev,stat);
+    
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = block;
+      break;
+    }
+    block           += block_size;
+    unlock_count    -= block_size;
+    
+#ifdef CYGSEM_IO_FLASH_CHATTER
+    dev->pf(".");
+#endif
+  }
+  FLASH_Disable(flash_base, end_addr);
   HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("\n");
@@ -710,86 +830,10 @@ cyg_flash_lock(const cyg_flashaddr_t fla
     return stat;
   }
   
-  if (flash_base + len - 1 > dev->end) {        
-    // The region to erase if bigger than this driver handles. Recurse
+  // Recurse if necessary for the next device
+  if (len > (dev->end + 1 - flash_base)) {
     return cyg_flash_lock(dev->end+1, 
-                          len - (dev->end - flash_base) - 1,
-                          err_address);
-  }
-  return CYG_FLASH_ERR_OK;
-}
-
-__externC int 
-cyg_flash_unlock(const cyg_flashaddr_t flash_base, 
-                 const size_t len, 
-                 cyg_flashaddr_t *err_address)
-{
-  cyg_flashaddr_t block, end_addr, addr;
-  struct cyg_flash_dev * dev;
-  size_t block_size;
-  int stat = CYG_FLASH_ERR_OK;
-  int d_cache, i_cache;
-  
-  if (!init) return CYG_FLASH_ERR_NOT_INIT;
-  
-#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-  if (plf_flash_query_soft_wp(addr,len))
-    return CYG_FLASH_ERR_PROTECT;
-#endif
-  
-  for (dev = flash_head; 
-       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
-       dev=dev->next)
-    ;
-  if (!dev) return CYG_FLASH_ERR_INVALID;
-  if (!dev->funs->flash_block_unlock) return CYG_FLASH_ERR_INVALID;
-  
-#ifdef CYGPKG_KERNEL
-  cyg_mutex_lock(&dev->mutex);
-#endif
-  addr = flash_base;
-  end_addr = flash_base + len - 1;
-  if (end_addr > dev->end) {
-    end_addr = dev->end;
-  }
-  
-  block =   block = flash_block_begin(addr, dev);
-  
-#ifdef CYGSEM_IO_FLASH_CHATTER
-  dev->pf("... Unlocking from %p-%p: ", (void*)block, (void*)end_addr);
-#endif
-  
-  HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-  FLASH_Enable(block, end_addr);
-  while (block <= end_addr) {
-    stat = dev->funs->flash_block_unlock(dev,block);
-    stat = dev->funs->flash_hwr_map_error(dev,stat);
-    
-    if (CYG_FLASH_ERR_OK != stat && err_address) {
-      *err_address = block;
-      break;
-    }
-    block += flash_block_size(dev, addr);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    dev->pf(".");
-#endif
-  }
-  FLASH_Disable(block, end_addr);
-  HAL_FLASH_CACHES_ON(d_cache, i_cache);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-  dev->pf("\n");
-#endif
-#ifdef CYGPKG_KERNEL
-  cyg_mutex_unlock(&dev->mutex);
-#endif
-  if (stat != CYG_FLASH_ERR_OK) {
-    return stat;
-  }
-  
-  if (flash_base + len - 1 > dev->end) {        
-    // The region to erase if bigger than this driver handles. Recurse
-    return cyg_flash_lock(dev->end+1, 
-                          len - (dev->end - flash_base) - 1,
+                          len - (dev->end + 1 - flash_base),
                           err_address);
   }
   return CYG_FLASH_ERR_OK;