changeset 1706:3845779eca10

* src/flash.c: Major rewrite to implement a new API * src/legacy_api.c: Support the legacy API * src/legacy_drv.c: Support the legacy driver API * src/flashiodev.c: Support the new API and multiple devices * include/flash_priv.h: Interface devices should use * cdl/io_flash.cdl: Updates for new interface and multiple devices.
author asl
date Thu, 05 Aug 2004 13:50:00 +0000
parents 99834d6b6eeb
children 0943943e5b80
files packages/io/flash/current/ChangeLog packages/io/flash/current/cdl/io_flash.cdl packages/io/flash/current/doc/flash.sgml packages/io/flash/current/include/flash.h packages/io/flash/current/include/flash_priv.h packages/io/flash/current/src/flash.c packages/io/flash/current/src/flashiodev.c packages/io/flash/current/src/legacy_api.c packages/io/flash/current/src/legacy_dev.c
diffstat 9 files changed, 2393 insertions(+), 773 deletions(-) [+]
line wrap: on
line diff
--- a/packages/io/flash/current/ChangeLog
+++ b/packages/io/flash/current/ChangeLog
@@ -1,3 +1,12 @@
+2004-08-05  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flash.c: Major rewrite to implement a new API
+	* src/legacy_api.c: Support the legacy API
+	* src/legacy_drv.c: Support the legacy driver API
+	* src/flashiodev.c: Support the new API and multiple devices
+	* include/flash_priv.h: Interface devices should use
+	* cdl/io_flash.cdl: Updates for new interface and multiple devices.
+	
 2004-06-20  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/flash.c (flash_read): Don't check if the flash is write 
--- a/packages/io/flash/current/cdl/io_flash.cdl
+++ b/packages/io/flash/current/cdl/io_flash.cdl
@@ -10,6 +10,7 @@
 ## This file is part of eCos, the Embedded Configurable Operating System.
 ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 ## Copyright (C) 2003 Gary Thomas
+## Copyright (C) 2004 Andrew Lunn
 ##
 ## 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
@@ -83,7 +84,7 @@ cdl_package CYGPKG_IO_FLASH {
             Use of this interface is deprecated.
             Drivers should make sure that the functions are
             linked to RAM by putting them in .2ram sections."
-	    requires !CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM
+            requires !CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM
     }
 
     cdl_interface CYGHWR_IO_FLASH_BLOCK_LOCKING {
@@ -94,6 +95,22 @@ cdl_package CYGPKG_IO_FLASH {
             locking (write-protection) of individual blocks."
     }
 
+    cdl_interface CYGHWR_IO_FLASH_DEVICE_LEGACY {
+        display       "Hardware driver uses the legacy interface"
+        flavor        booldata
+        description   "
+            The flash device driver implements the legacy interface to the 
+            flash library"
+    }
+
+    cdl_interface CYGHWR_IO_FLASH_DEVICE_V2 {
+        display       "Hardware driver uses the V2 interface"
+        flavor        booldata
+        description   "
+            The flash device driver implements the V2 interface to the 
+            flash library"
+    }
+        
     cdl_option CYGSEM_IO_FLASH_READ_INDIRECT {
         display       "Hardware cannot support direct access to FLASH memory"
         flavor        bool
@@ -134,6 +151,27 @@ cdl_package CYGPKG_IO_FLASH {
            write-protected or not."
     }
 
+
+    cdl_option CYGSEM_IO_FLASH_LEGACY_API {
+        display          "Provide the legacy user API"
+        flavor           bool
+        default_value    1
+        compile          legacy_api.c
+        description      "
+            Provide an implementation of the lagacy user API. This is mapped 
+            onto the new API via a small layer of code"
+    }
+        
+    cdl_option CYGSEM_IO_FLASH_LEGACY_DEVICE_API {
+        display          "Provide the legacy device API"
+        flavor           bool
+        default_value    CYGHWR_IO_FLASH_DEVICE_LEGACY
+        compile          -library=libextras.a legacy_dev.c
+        description      "
+            Provide an implementation of the legacy device API. This can be 
+            used to interface to one legacy device."
+    }
+    
     cdl_component CYGPKG_IO_FLASH_BLOCK_DEVICE {
         display         "Instantiate in I/O block device API"
         flavor          bool
@@ -145,54 +183,164 @@ cdl_package CYGPKG_IO_FLASH {
                 API ( cyg_io_read() etc. )"
 
         cdl_component CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1 {
-			display       "Name of flash device 1 block device"
+            display       "Name of flash device 1 block device"
             flavor        data
             default_value { "\"/dev/flash1\"" }
                 
-			cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_1 {
-				requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_1
-				no_define
-			}
+            cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_1 {
+                  requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_1
+                  no_define
+            }
+
+            cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_1 {
+                  display       "Static configuration via offset"
+                  default_value 1
+                  implements    CYGINT_IO_FLASH_BLOCK_CFG_1
+                  description   "
+                        This configures the flash device 1 block device
+                        with static offset from the base of the first
+                        flash device and length"
+                        
+                  cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_1 {
+                      display         "Start offset from flash base"
+                      flavor          data
+                      default_value   0x100000
+                      description     "
+                            This gives the offset from the base of flash 
+                            of the first flash device which this block device 
+                            corresponds to."
+                  }
+                  cdl_option CYGNUM_IO_FLASH_BLOCK_LENGTH_1 {
+                      display         "Length"
+                      flavor          data
+                      default_value   0x100000
+                      description     "
+                            This gives the length of the region of flash given over
+                            to this block device."
+                  }
+            }
+            cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_1 {
+                  display       "Absolute static configuration"
+                  default_value 0
+                  implements    CYGINT_IO_FLASH_BLOCK_CFG_1
+                  description   "
+                        This configures the flash device 1 block device
+                        with absolute base address and a length"
+                        
+                   cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_1 {
+                       display         "Start offset from flash base"
+                       flavor          data
+                       default_value   0x4000000
+                       description     "
+                             This gives the absolute address in flash which this
+                             block device corresponds to."
+                   }
+                   cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_1 {
+                       display         "Length"
+                       flavor          data
+                       default_value   0x100000
+                       description     "
+                             This gives the length of the region of flash given over
+                             to this block device."
+                   }
+             }
+             cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 {
+                    display       "Configuration from FIS"
+                    default_value 0
+                    implements    CYGINT_IO_FLASH_BLOCK_CFG_1
+                    description   "
+                          This configures the flash device 1 block device
+                          from Redboot FIS"
+                                       
+                     cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1 {
+                            display       "Name of FIS entry"
+                            flavor        data
+                            default_value { "\"jffs2\"" }   
+                     }
+            }        
+        }        
+        cdl_component CYGSEM_IO_FLASH_BLOCK_DEVICE_2 {
+               display       "Implements a second block device"
+               default_value 0
 
-			cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_1 {
-				display       "Static configuration"
-				default_value 1
-				implements    CYGINT_IO_FLASH_BLOCK_CFG_1
-				description   "
-					This configures the flash device 1 block device
-					with static base and length"
-			
-				cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_1 {
-					display         "Start offset from flash base"
-					flavor          data
-					default_value   0x100000
-					description     "
-						This gives the offset from the base of flash which this
-						block device corresponds to."
-					}
-					cdl_option CYGNUM_IO_FLASH_BLOCK_LENGTH_1 {
-					display         "Length"
-					flavor          data
-					default_value   0x100000
-					description     "
-						This gives the length of the region of flash given over
-						to this block device."
-					}
-				}
-			cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 {
-				display       "Configuration from FIS"
-				default_value 0
-				implements    CYGINT_IO_FLASH_BLOCK_CFG_1
-				description   "
-					This configures the flash device 1 block device
-					from Redboot FIS"
-					
-				cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1 {
-					display       "Name of FIS entry"
-					flavor        data
-					default_value { "\"jffs2\"" }	
-				}
-            }        
-        }
-    }
-}
+               cdl_component CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_2 {
+               display       "Name of flash device 2 block device"
+               flavor        data
+               default_value { "\"/dev/flash2\"" }
+                
+               cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_2 {
+                             requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_2
+                             no_define
+               }
+
+               cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_2 {
+                      display       "Static configuration via offset"
+                      default_value 1
+                      implements    CYGINT_IO_FLASH_BLOCK_CFG_2
+                      description   "
+                            This configures the flash device 2 block device
+                            with static offset from the base of the first
+                            flash device and length"
+                        
+                      cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_2 {
+                            display         "Start offset from flash base"
+                            flavor          data
+                            default_value   0x100000
+                            description     "
+                                  This gives the offset from the base of flash 
+                                  of the first flash device which this block device 
+                                  corresponds to."
+                      }
+                      cdl_option CYGNUM_IO_FLASH_BLOCK_LENGTH_2 {
+                            display         "Length"
+                            flavor          data
+                            default_value   0x100000
+                            description     "
+                                  This gives the length of the region of flash 
+                                  given over to this block device."
+                      }       
+               }
+               cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_2 {
+                      display       "Absolute static configuration"
+                      default_value 0
+                      implements    CYGINT_IO_FLASH_BLOCK_CFG_2
+                      description   "
+                            This configures the flash device 2 block device
+                            with absolute base address and a length"
+                        
+                      cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_2 {
+                            display         "Start offset from flash base"
+                            flavor          data
+                            default_value   0x4000000
+                            description     "
+                                  This gives the absolute address in flash which this
+                                  block device corresponds to."
+                      }
+                      cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_2 {
+                            display         "Length"
+                            flavor          data
+                            default_value   0x100000
+                            description     "
+                                  This gives the length of the region of flash 
+                                  given over to this block device."
+                      }
+               }
+
+               cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_2 {
+                      display       "Configuration from FIS"
+                      default_value 0
+                      implements    CYGINT_IO_FLASH_BLOCK_CFG_2
+                      description   "
+                            This configures the flash device 2 block device
+                            from Redboot FIS"
+                                       
+                      cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_2 {
+                            display       "Name of FIS entry"
+                            flavor        data
+                            default_value { "\"jffs2-2\"" }   
+                      }
+               }        
+            }
+         }
+     }
+}
\ No newline at end of file
--- a/packages/io/flash/current/doc/flash.sgml
+++ b/packages/io/flash/current/doc/flash.sgml
@@ -35,9 +35,6 @@
 <TITLE>The eCos FLASH Library</TITLE>
 <PARA>The FLASH library is an optional part of eCos, and is only
 	applicable to some platforms.</PARA>
-<SECT1 id="flash-library">
-<TITLE>FLASH Library</TITLE>
-
 <PARA>The eCos FLASH library provides the following functionality:</PARA>
 
 <orderedlist>
@@ -50,6 +47,340 @@
           <PARA></listitem>
 </orderedlist>
 
+<PARA> There are two APIs with the flash library. The old API is
+retained for backwards compatibility reasons, but should slowly be
+replaced with the new API which is much more flexible and does not
+pollute the name space as much.
+</PARA>
+
+<SECT1>
+<TITLE>Notes on using the FLASH library</TITLE>
+
+<PARA>FLASH devices cannot be read from when an erase or write
+operation is active. This means it is not possible to execute code
+from flash while an erase or write operation is active. It is possible
+to use the library when the executable image is resident in FLASH. The
+low level drivers are written such that the linker places the
+functions that actually manipulate the flash into RAM.  However the
+library may not be interrupt safe. An interrupt must not cause
+execution of code that is resident in FLASH. This may be the image
+itself, or RedBoot. In some configurations of eCos, ^C on the serial
+port or debugging via Ethernet may cause an interrupt handler to call
+RedBoot. If RedBoot is resident in FLASH this will cause a crash.
+Similarly, if another thread invokes a virtual vector function to
+access RedBoot, eg to perform a <FUNCTION>diag_printf()</FUNCTION> a
+crash could result.
+</PARA>
+
+<PARA> Thus with a ROM based image or a ROM based Redboot it is
+recommended to disable interrupts while erasing or programming
+flash. Using both a ROMRAM or RAM images and a ROMRAM or RAM RedBoot
+are safe and there is no need to disable interrupts. Similarly, 
+</PARA>
+</SECT1>
+
+<SECT1>
+<TITLE>Danger, Will Robinson! Danger!</TITLE>
+
+<PARA>Unlike nearly every other aspect of embedded system programming,
+getting it wrong with FLASH devices can render your target system
+useless. Most targets have a boot loader in the FLASH. Without this
+boot loader the target will obviously not boot. So before starting to
+play with this library its worth investigating a few things. How do
+you recover your target if you delete the boot loader? Do you have the
+necessary JTAG cable? Or is specialist hardware needed? Is it even
+possible to recover the target boards or must it be thrown into the
+rubbish bin? How does killing the board affect your project schedule?
+</PARA>
+
+</SECT1>
+</CHAPTER>
+
+<CHAPTER id="ecos-flash-v2">
+<TITLE>The Version 2 eCos FLASH API</TITLE>
+
+<PARA> There are two APIs described here. The first is the application
+API which programs should use. The second API is that between the
+FLASH IO library and the device drivers. </PARA>
+
+<SECT1 id="ecos-flash-v2-api">
+<TITLE>FLASH user API</TITLE>
+<PARA> 
+
+<PARA>All of the functions described below are declared in the header
+file <filename>&lt;cyg/io/flash.h.h&gt;</filename> which all users of
+the FLASH library should include.</PARA>
+
+<SECT2>
+<TITLE>Initializing the FLASH library</TITLE>
+
+<PARA>The FLASH library needs to be initialized before other FLASH
+operations can be performed. This only needs to be done once. The
+following function will only do the initialization once so it's safe
+to call multiple times: </PARA>
+
+<PROGRAMLISTING>__externC int cyg_flash_init(const cyg_flash_printf *pf); 
+typedef int cyg_flash__printf(const char *fmt, ...); </PROGRAMLISTING>
+
+<PARA>
+The parameter <parameter>pf</parameter> is a pointer to a function
+which is to be used for diagnostic output. Typically the function
+<function>diag_printf()</function> will be passed. Normally this
+function is not used by the higher layer of the library unless
+<literal>CYGSEM_IO_FLASH_CHATTER</literal> is enabled.  Passing a
+<parameter>NULL</parameter> is not recommended, even when
+CYGSEM_IO_FLASH_CHATTER is disabled. The lower layers of the library
+may unconditionally call this function, especially when errors occur,
+probably resulting in a more serious error/crash!.</PARA>
+</SECT2>
+
+<SECT2>
+<TITLE>Retrieving information about FLASH devices</TITLE> 
+
+<PARA>
+The following five functions return information about the FLASH.
+</PARA>
+
+<PROGRAMLISTING>
+__externC int cyg_flash_get_info(cyg_uint32 devno, cyg_flash_info_t * info);
+__externC int cyg_flash_get_info_addr(cyg_flashaddr_t flash_base, cyg_flash_info_t * info);
+__externC int cyg_flash_verify_addr(const flashaddr_t address);
+__externC int cyg_flash_code_overlaps(const flashaddr_t start, const flashaddr_t end);
+__externC int cyg_flash_get_block_info(size_t *block_size, cyg_uint32 *blocks);
+__externC int cyg_flash_get_limits(flashaddr_t *start, flashaddr_t *end);
+__extern size_t cyg_flash_block_size(const cyg_flashaddr_t flash_base);
+
+typedef struct cyg_block_info
+    size_t                    block_size;
+    cyg_unit32                blocks;
+} cyg_block_info_t;
+
+typedef struct {
+    flashaddr_t               start;          // First address
+    flashaddr_t               end;            // Last address
+    cyg_uint32                num_block_infos // Number of entries
+    cyg_block_info_t          *blocks_info;   // Info about one block size
+} cyg_flash_info_t;
+</PROGRAMLISTING>
+
+<PARA><FUNCTION>cyg_flash_get_info()</FUNCTION> is the main function
+to get information about installed flash devices.  Parameter
+<PARAMETER>devno</PARAMETER> is used to iterate over the available
+flash devices, starting from 0. If the devno'th device exists, the
+structure pointed to by <PARAMETER>info</PARAMETER> is filled in and
+<LITERAL>CYG_FLASH_ERR_OK</LITERAL> is returned, otherwise
+<LITERAL>CYG_FLASH_ERR_INVALID</LITERAL>.
+<FUNCTION>cyg_flash_get_info()</FUNCTION> if similar, but returns the
+information about the flash device at the given address.
+<FUNCTION>cyg_flash_block_size()</FUNCTION> returns the size of the
+block at the given address.  <FUNCTION>cyg_flash_verify_addr()
+</FUNCTION> tests if the target addresses is within one of the FLASH
+devices, returning <LITERAL>CYG_FLASH_ERR_OK </LITERAL> if so.
+<FUNCTION> cyg_flash_code_overlaps() </FUNCTION> checks if the
+executing code is resident in the section of flash indicated by
+<PARAMETER>start</PARAMETER> and <PARAMETER> end </PARAMETER>.  If
+this function returns <LITERAL>CYG_FLASH_ERR_OK</LITERAL> the code is
+inside the address refion given. Erase and program operations within
+this range are very likely to cause the target to crash and burn
+horribly. Note the FLASH library does allow you to shoot yourself in
+the foot in this way.</PARA>
+
+<PARA>To aid with backwards compatibility the following functions have
+been retained from the V1 API. However the only operate on the first
+FLASH driver.  The function <FUNCTION>cyg_flash_get_block_info()
+</FUNCTION> returns the size and number of blocks for the first
+driver. When the device has a mixture of block sizes, the size of the
+"normal" block will be returned. Please read the source code to
+determine exactly what this means.  <FUNCTION> cyg_flash_get_limits()
+</FUNCTION> returns the lower and upper memory address the first FLASH
+occupies.  
+</SECT2>
+ <SECT2>
+
+<TITLE>Reading from FLASH</TITLE>
+
+<PARA>
+There are two methods for reading from FLASH. The first is to use the
+following function. </PARA>
+
+<PROGRAMLISTING>
+__externC int cyg_flash_read(flashaddr_t *flash_base, const void *ram_base, const size_t len, flashaddr_t **err_address);
+</PROGRAMLISTING>
+
+<PARA>
+<PARAMETER>flash_base</PARAMETER> is where in the flash to read
+from. <PARAMETER>ram_base</PARAMETER> indicates where the data read
+from flash should be placed into RAM. <PARAMETER>len</PARAMETER> is
+the number of bytes to be read from the FLASH and
+<PARAMETER>err_address</PARAMETER> is used to return the location in
+FLASH that any error occurred while reading.
+</PARA>
+
+<PARA>
+The second method is to simply <FUNCTION>memcpy()</FUNCTION> directly
+from the FLASH. This is not recommended since some types of device
+cannot be read in this way, eg NAND FLASH. Using the FLASH library
+function to read the FLASH will always work so making it easy to port
+code from one FLASH device to another.
+</PARA>
+
+</SECT2>
+<SECT2>
+
+<TITLE>Erasing areas of FLASH</TITLE>
+
+<PARA>
+Blocks of FLASH can be erased using the following function:
+</PARA>
+
+<PROGRAMLISTING>__externC int cyg_flash_erase(flashaddr_t *flash_base, const size_t len, flashaddr_t **err_address);
+</PROGRAMLISTING>
+
+<PARA>
+<PARAMETER>flash_base</PARAMETER> is where in the flash to erase
+from. <PARAMETER>len</PARAMETER> is the minimum number of bytes to
+erase in the FLASH and <PARAMETER>err_address</PARAMETER> is used to
+return the location in FLASH that any error occurred while erasing. It
+should be noted that FLASH devices are block oriented when erasing. It
+is not possible to erase a few bytes within a block, the whole block
+will be erased. <PARAMETER>flash_base</PARAMETER> may be anywhere
+within the first block to be erased and <PARAMETER>flash_base+len
+</PARAMETER> maybe anywhere in the last block to be erased.  </PARA>
+
+</SECT2>
+<SECT2>
+
+<TITLE>Programming the FLASH</TITLE>
+
+<PARA> Programming of the flash is achieved using the following
+function.</PARA>
+
+<PROGRAMLISTING>__externC int cyg_flash_program(const flashaddr_t *flash_base, void *ram_base, const size_t len, flashaddr_t **err_address);
+</PROGRAMLISTING>
+
+<PARA>
+<PARAMETER>flash_base</PARAMETER> is where in the flash to program
+from. <PARAMETER>ram_base</PARAMETER> indicates where the data to be
+programmed into FLASH should be read from in RAM. <PARAMETER>len
+</PARAMETER> is the number of bytes to be program into the FLASH and
+<PARAMETER>err_address</PARAMETER> is used to return the location in
+FLASH that any error occurred while programming. </PARA>
+
+</SECT2>
+<SECT2>
+
+<TITLE>Locking and unlocking blocks</TITLE>
+
+<PARA>
+Some flash devices have the ability to lock and unlock blocks. A
+locked block cannot be erased or programmed without it first being
+unlocked. For devices which support this feature and when <LITERAL>
+CYGHWR_IO_FLASH_BLOCK_LOCKING</LITERAL> is enabled then the following
+two functions are available:</PARA>
+
+<PROGRAMLISTING>
+__externC int cyg_flash_lock(const flashaddr_t *flash_base, const size_t len, flashaddr_t **err_address);
+__externC int cyg_flash_unlock(const flashaddr_t *flash_base, const size_t len, flashaddr_t **err_address);
+</PROGRAMLISTING>
+
+</SECT2>
+
+<SECT2>
+<TITLE>Locking FLASH Mutex's</TITLE>
+
+<PARA>When the eCos kernel package is included in the eCos
+configuration, the FLASH IO library will perform mutex locking on
+FLASH operations. This makes the API defined here thread safe. However
+applications may wish to directly access the contents of the FLASH. In
+order for this to be thread safe it is necessary for the application
+to use the following two functions to inform the FLASH IO library that
+the FLASH devices are being used and other API calls should be
+blocked.</PARA>
+
+<PROGRAMLISTING>
+__externC int cyg_flash_mutex_lock(const flashaddr_t *from, const size_t len);
+__externC int cyg_flash_mutex_unlock(const flashaddr_t *from, const size_t len);
+</PROGRAMLISTING>
+
+<SECT2>
+
+<TITLE>Return values and errors</TITLE>
+
+<PARA>All the functions above, except <FUNCTION>cyg_flash_code_overlaps()
+</FUNCTION> return one of the following return values.</PARA>
+
+<PROGRAMLISTING>
+CYG_FLASH_ERR_OK              No error - operation complete
+CYG_FLASH_ERR_INVALID         Invalid FLASH address
+CYG_FLASH_ERR_ERASE           Error trying to erase
+CYG_FLASH_ERR_LOCK            Error trying to lock/unlock
+CYG_FLASH_ERR_PROGRAM         Error trying to program
+CYG_FLASH_ERR_PROTOCOL        Generic error
+CYG_FLASH_ERR_PROTECT         Device/region is write-protected
+CYG_FLASH_ERR_NOT_INIT        FLASH info not yet initialized
+CYG_FLASH_ERR_HWR             Hardware (configuration?) problem
+CYG_FLASH_ERR_ERASE_SUSPEND   Device is in erase suspend mode
+CYG_FLASH_ERR_PROGRAM_SUSPEND Device is in program suspend mode
+CYG_FLASH_ERR_DRV_VERIFY      Driver failed to verify data
+CYG_FLASH_ERR_DRV_TIMEOUT     Driver timed out waiting for device
+CYG_FLASH_ERR_DRV_WRONG_PART  Driver does not support device
+CYG_FLASH_ERR_LOW_VOLTAGE     Not enough juice to complete job
+</PROGRAMLISTING>
+
+<PARA>To turn an error code into a human readable string the following
+function can be used:</PARA>
+
+<PROGRAMLISTING>__externC const char *cyg_flash_errmsg(const int err);
+</PROGRAMLISTING>
+</SECT2>
+
+<SECT1 id="ecos-flash-v2-dev">
+<TITLE>FLASH device API</TITLE> <PARA>This section describes the API
+between the FLASH IO library the FLASH device drivers.</PARA>
+
+<SECT2>
+<TITLE>The FLASH device Structure</TITLE>
+
+<PARA>This structure keeps all the information about a single driver.</PARA>
+
+<PROGRAMLISTING>struct cyg_flash_dev {
+    struct cyg_flash_dev_funs *funs;           // Function pointers
+    flashaddr_t               *start;          // First address
+    flashaddr_t               *end;            // Last address
+    void                      *priv;           // Devices private data
+    cyg_uint32                num_block_infos; // Number of entries
+    cyg_block_info_t          *blocks_info;    // Info about one block size
+
+
+// The following are only written to by the FLASH IO layer.
+    cyg_flash_printf          *pf;             // Pointer to diagnostic printf
+    cyg_bool                  init;            // Device has been initialized
+#ifdef CYG_KERNEL
+    cyg_mutex_t               mutex;           // Mutex for thread safeness
+#endif
+    struct cyg_flash_dev      *next;           // Pointer to next device
+}
+
+struct cyg_flash_dev_funs {
+    int (*flash_init) (struct cyg_flash_dev *dev);
+    size_t (*flash_query) (struct cyg_flash_dev *dev, void * data, const size_t len);
+    int (*flash_erase_block) (struct cyg_flash_dev *dev, const flashaddr_t *block_base);
+    int (*flash_program) (struct cyg_flash_dev *dev, flashaddr_t *base, const void* data, const size_t len);
+    int (*flash_read) (struct cyg_flash_dev *dev, const flashaddr_t *base, void* data, const size_t len);
+    int (*flash_hwr_map_error) (struct cyg_flash_dev *dev, int err);
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+    int (*flash_block_lock) (struct cyg_flash_dev *dev, const flashaddr_t *block_base);
+    int (*flash_block_unlock) (struct cyg_flash_dev *dev, const flashaddr_t *block_base);
+#endif
+}
+</PROGRAMLISTING>
+
+<PARA>The FLASH IO layer will only pass requests for operations on a single block.
+</SECT1>
+</CHAPTER>
+
+<CHAPTER id="ecos-flash-v1">
+<TITLE>The legacy Version 1 eCos FLASH API</TITLE>
 <PARA>
 The library has a number of limitations:</PARA>
 
@@ -72,10 +403,18 @@ The library has a number of limitations:
 </listitem>
 </orderedlist>
 
+<PARA> There are two APIs described here. The first is the application
+API which programs should use. The second API is that between the
+FLASH io library and the device drivers. </PARA>
+
+<SECT1 id="ecos-flash-v1-api">
+<TITLE>FLASH user API</TITLE>
+
 <PARA>All of the functions described below are declared in the header
 file <filename>&lt;cyg/io/flash.h.h&gt;</filename> which all users of
 the FLASH library should include.</PARA>
 
+
 <SECT2>
 <TITLE>Initializing the FLASH library</TITLE>
 
@@ -84,8 +423,8 @@ operations can be performed. This only n
 following function will only do the initialization once so it's safe
 to call multiple times: </PARA>
 
-<PROGRAMLISTING>externC int flash_init( _printf *pf ); typedef int
-_printf(const char *fmt, ...); </PROGRAMLISTING>
+<PROGRAMLISTING>externC int flash_init( _printf *pf ); 
+typedef int _printf(const char *fmt, ...); </PROGRAMLISTING>
 
 <PARA>
 The parameter <parameter>pf</parameter> is a pointer to a function
@@ -266,45 +605,178 @@ its library functions will likely fail a
 the callers responsibility to use the necessary mutex's if needed.
 <PARA>
 
-<PARA>FLASH devices cannot be read from when an erase or write
-operation is active. This means it is not possible to execute code
-from flash while an erase or write operation is active. It is possible
-to use the library when the executable image is resident in FLASH. The
-low level drivers are written such that the linker places the
-functions that actually manipulate the flash into RAM.  However the
-library may not be interrupt safe. An interrupt must not cause
-execution of code that is resident in FLASH. This may be the image
-itself, or RedBoot. In some configurations of eCos, ^C on the serial
-port or debugging via Ethernet may cause an interrupt handler to call
-RedBoot. If RedBoot is resident in FLASH this will cause a crash.
-Similarly, if another thread invokes a virtual vector function to
-access RedBoot, eg to perform a <FUNCTION>diag_printf()</FUNCTION> a
-crash could result.
+</SECT2>
+</SECT1>
+
+<SECT1 id="ecos-flash-v1-dev">
+<TITLE>FLASH device API</TITLE> <PARA>This section describes the API
+between the FLASH IO library the FLASH device drivers.</PARA>
+
+<SECT2>
+<TITLE>The flash_info structure</TITLE>
+
+<PARA> The <parameter>flash_info</parameter>structure is used by both
+the FLASH IO library and the device driver.</PARA>
+<PROGRAMLISTING>struct flash_info {
+    int   block_size;   // Assuming fixed size "blocks"
+    int   blocks;       // Number of blocks
+    int   buffer_size;  // Size of write buffer (only defined for some devices)
+    unsigned long block_mask;
+    void *start, *end;  // Address range
+    int   init;         // FLASH API initialised
+    _printf *pf;        // printf like function for diagnostics
+};
+</PROGRAMLISTING>
+
+<PARA>block_mask is used internally in the FLASH IO library. It
+contains a mask which can be used to turn an arbitrary address in
+flash to the base address of the block which contains the
+address.</PARA>
+
+<PARA>There exists one global instance of this structure with the name
+<parameter>flash_info</parameter>. All calls into the device driver
+makes use of this global structure to maintain state.</PARA>
+
+</SECT2>
+
+<SECT2>
+<TITLE>Initializing the device driver</TITLE>
+
+<PARA>The FLASH IO library will call the following function to
+initialize the device driver:</PARA>
+
+<PROGRAMLISTING>externC int  flash_hwr_init(void);
+</PROGRAMLISTING>
+
+<PARA>The device driver should probe the hardware to see if the FLASH
+devices exist. If it does it should fill in <parameter>start, end,
+blocks and block_size.</parameter>If the FLASH contains a write buffer
+the size of this should be placed in <parameter>buffer_size
+</parameter>. On successful probing the function should return
+<literal>FLASH_ERR_OK</literal>. When things go wrong it can be
+assumed that <parameter>pf</parameter> points to a printf like
+function for outputting error messages.
 </PARA>
+</SECT2>
 
-<PARA> Thus with a ROM based image or a ROM based Redboot it is
-recommended to disable interrupts while erasing or programming
-flash. Using both a ROMRAM or RAM images and a ROMRAM or RAM RedBoot
-are safe and there is no need to disable interrupts. Similarly, 
-</PARA>
+<SECT2>
+<TITLE>Querying the FLASH</TITLE>
+
+<PARA>FLASH devices can be queried to return there manufacture ID,
+size etc. This function allows this information to be returned.</PARA>
+
+<PROGRAMLISTING>int flash_query(unsigned char *data);</PROGRAMLISTING>
+
+<PARA>The caller must know the size of data to be returned and provide
+an appropriately sized buffer pointed to be parameter
+<parameter>data</parameter>. This function is generally used by
+<function>flash_hwr_init()</function>.</PARA>
+
+</SECT2>
+<SECT2>
+<TITLE>Erasing a block of FLASH</TITLE>
+
+<PARA>So that the FLASH IO layer can erase a block of FLASH the
+following function should be provided.</PARA>
+
+<PROGRAMLISTING>int flash_erase_block(volatile flash_t *block, unsigned int block_size);
+</PROGRAMLISTING>
 
 </SECT2>
 <SECT2>
+<TITLE>Programming a region of FLASH</TITLE>
 
-<TITLE>Danger, Will Robinson! Danger!</TITLE>
+<PARA>The following function must be provided so that data can be
+written into the FLASH.</PARA>
+
+<PROGRAMLISTING>int flash_program_buf(volatile flash_t *addr, flash_t *data, int len,
+                  unsigned long block_mask, int buffer_size);</PROGRAMLISTING>
+
+<PARA>The device will only be asked to program data in one block of
+the flash. The FLASH IO layer will break longer user requests into a
+smaller writes.</PARA>
+
+<SECT2>
+<TITLE>Reading a region from FLASH</TITLE>
+
+<PARA>Some FLASH devices are not memory mapped so it is not possible
+to read there contents directly. The following function read a region
+of FLASH.</PARA>
+
+<PROGRAMLISTING>int flash_read_buf(volatile flash_t* addr, flash_t* data, int len);
+</PROGRAMLISTING>
 
-<PARA>Unlike nearly every other aspect of embedded system programming,
-getting it wrong with FLASH devices can render your target system
-useless. Most targets have a boot loader in the FLASH. Without this
-boot loader the target will obviously not boot. So before starting to
-play with this library its worth investigating a few things. How do
-you recover your target if you delete the boot loader? Do you have the
-necessary JTAG cable? Or is specialist hardware needed? Is it even
-possible to recover the target boards or must it be thrown into the
-rubbish bin? How does killing the board affect your project schedule?
-</PARA>
+<PARA>As with writing to the flash, the FLASH IO layer will break
+longer user requests for data into a number of reads which are at
+maximum one block in size.</PARA>
+
+<PARA>A device which cannot be read directy should set
+<LITERAL>CYGSEM_IO_FLASH_READ_INDIRECT</LITERAL> so that the IO layer
+makes use of the <function>flash_read_buf()</function>function.
+
+</SECT2> 
+
+<SECT2>
+<TITLE>Locking and unlocking FLASH blocks</TITLE>
+
+<PARA>Some flash devices allow blocks to be locked so that they cannot
+be written to. The device driver should provide the following
+functions to manipulate these locks.</PARA>
+
+<PROGRAMLISTING>int flash_lock_block(volatile flash_t *block);
+int flash_unlock_block(volatile flash_t *block, int block_size, int blocks);
+</PROGRAMLISTING>
+
+<PARA>These functions are only used if
+<LITERAL>CYGHWR_IO_FLASH_BLOCK_LOCKING</LITERAL></PARA>
 
 </SECT2>
-</SECT1> 
+
+<SECT2>
+<TITLE>Mapping FLASH error codes to FLASH IO error codes</TITLE>
+
+<PARA>The functions <function>flash_erase_block(),
+flash_program_buf(), flash_read_buf(), flash_lock_block() and
+flash_unlock_block()</function> return an error code which is specific
+to the flash device. To map this into a FLASH IO error code, the
+driver should provide the following function: </PARA>
+
+<PROGRAMLISTING>int flash_hwr_map_error(int err);</PROGRAMLISTING>
+
+</SECT2>
+
+<SECT2>
+<TITLE>Determining if code is in FLASH</TITLE>
+
+<PARA>Although a general function, the device driver is expected to
+provide the implementation of the function
+<function>flash_code_overlaps()</function>.</PARA>
+
+</SECT2>
+
+<SECT2>
+<TITLE>Implementation Notes</TITLE>
+
+<PARA>The FLASH IO layer will manipulate the caches as required. The
+device drivers do not need to enable/disable caches when performing
+operations of the FLASH.<PARA>
+
+<PARA>Device drivers should keep all chatter to a minimum when
+<literal>CYGSEM_IO_FLASH_CHATTER</literal> is not defined. All output
+should use the print function in the <parameter>pf</parameter> in
+<parameter>flash_info</parameter> and not
+<function>diag_printf()</function></PARA>
+
+<PARA>Device driver functions which manipulate the state of the flash
+so that it cannot be read from for program execute need to ensure
+there code is placed into RAM. The linker will do this if the
+appropriate attribute is added to the function. e.g:</PARA>
+
+<PROGRAMLISTING>int flash_program_buf(volatile flash_t *addr, flash_t *data, int len,
+                  unsigned long block_mask, int buffer_size)
+ __attribute__ ((section (".2ram.flash_program_buf")));</PROGRAMLISTING>
+
+</SECT2>
+</SECT1>
 </CHAPTER> 
 </PART>
--- a/packages/io/flash/current/include/flash.h
+++ b/packages/io/flash/current/include/flash.h
@@ -10,6 +10,7 @@
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2003 Gary Thomas
+// copyright (C) 2004 Andrew Lunn
 //
 // 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
@@ -42,7 +43,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, Andrew Lunn
 // Date:         2000-07-14
 // Purpose:      
 // Description:  
@@ -54,15 +55,94 @@
 #ifndef _IO_FLASH_H_
 #define _IO_FLASH_H_
 
+#include <pkgconf/system.h>
 #include <pkgconf/io_flash.h>
 #include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_tables.h>
+#ifdef CYGPKG_KERNEL
+#include <cyg/kernel/kapi.h>
+#endif
 
+typedef CYG_ADDRESS cyg_flashaddr_t;
+
+typedef struct cyg_block_info 
+{
+  size_t                    block_size;
+  cyg_uint32                blocks;
+} cyg_block_info_t;
+
+// Information about what one device driver drives
+typedef struct {
+  cyg_flashaddr_t           start;           // First address
+  cyg_flashaddr_t           end;             // Last address
+  cyg_uint32                num_block_infos; // Number of entries
+  cyg_block_info_t          *block_info;     // Info about block sizes
+} cyg_flash_info_t;
+
+typedef int cyg_flash_printf(const char *fmt, ...);
+__externC int cyg_flash_init( cyg_flash_printf *pf );
+__externC int cyg_flash_get_info(cyg_uint32 devno, 
+                                 cyg_flash_info_t * info);
+__externC int cyg_flash_get_info_addr(cyg_flashaddr_t flash_base, 
+                                      cyg_flash_info_t * info);
+__externC int cyg_flash_verify_addr(const cyg_flashaddr_t address);
+__externC bool cyg_flash_code_overlaps(const cyg_flashaddr_t start, 
+                                       const cyg_flashaddr_t end);
+__externC int cyg_flash_get_block_info(size_t *block_size, 
+                                       cyg_uint32 *blocks);
+__externC int cyg_flash_get_limits(cyg_flashaddr_t *start, 
+                                   cyg_flashaddr_t *end);
+__externC size_t cyg_flash_block_size(const cyg_flashaddr_t flash_base);
+__externC int cyg_flash_read(cyg_flashaddr_t flash_base, 
+                             const void *ram_base, 
+                             const size_t len, 
+                             cyg_flashaddr_t *err_address);
+__externC int cyg_flash_erase(const cyg_flashaddr_t flash_base, 
+                              const size_t len, 
+                              cyg_flashaddr_t *err_address);
+__externC int cyg_flash_program(const cyg_flashaddr_t flash_base, 
+                                void *ram_base, 
+                                const size_t len, 
+                                cyg_flashaddr_t *err_address);
+__externC int cyg_flash_lock(const cyg_flashaddr_t flash_base, 
+                             const size_t len, 
+                             cyg_flashaddr_t *err_address);
+__externC int cyg_flash_unlock(const cyg_flashaddr_t flash_base, 
+                               const size_t len, 
+                               cyg_flashaddr_t *err_address);
+__externC const char *cyg_flash_errmsg(const int err);
+#ifdef CYGPKG_KERNEL
+__externC int cyg_flash_mutex_lock(const cyg_flashaddr_t from, 
+                                   const size_t len);
+__externC int cyg_flash_mutex_unlock(const cyg_flashaddr_t from, 
+                                     const size_t len);
+#endif
+
+#define CYG_FLASH_ERR_OK              0x00  // No error - operation complete
+#define CYG_FLASH_ERR_INVALID         0x01  // Invalid FLASH address
+#define CYG_FLASH_ERR_ERASE           0x02  // Error trying to erase
+#define CYG_FLASH_ERR_LOCK            0x03  // Error trying to lock/unlock
+#define CYG_FLASH_ERR_PROGRAM         0x04  // Error trying to program
+#define CYG_FLASH_ERR_PROTOCOL        0x05  // Generic error
+#define CYG_FLASH_ERR_PROTECT         0x06  // Device/region is write-protected
+#define CYG_FLASH_ERR_NOT_INIT        0x07  // FLASH info not yet initialized
+#define CYG_FLASH_ERR_HWR             0x08  // Hardware (configuration?) problem
+#define CYG_FLASH_ERR_ERASE_SUSPEND   0x09  // Device is in erase suspend mode
+#define CYG_FLASH_ERR_PROGRAM_SUSPEND 0x0a  // Device is in program suspend mode
+#define CYG_FLASH_ERR_DRV_VERIFY      0x0b  // Driver failed to verify data
+#define CYG_FLASH_ERR_DRV_TIMEOUT     0x0c  // Driver timed out 
+#define CYG_FLASH_ERR_DRV_WRONG_PART  0x0d  // Driver does not support device
+#define CYG_FLASH_ERR_LOW_VOLTAGE     0x0e  // Not enough juice to complete job
+
+#ifdef CYGSEM_IO_FLASH_LEGACY_API
 typedef int _printf(const char *fmt, ...);
 
 externC int flash_init(_printf *pf);
 externC int flash_erase(void *base, int len, void **err_address);
-externC int flash_program(void *flash_base, void *ram_base, int len, void **err_address);
-externC int flash_read(void *flash_base, void *ram_base, int len, void **err_address);
+externC int flash_program(void *flash_base, void *ram_base, int len, 
+                          void **err_address);
+externC int flash_read(void *flash_base, void *ram_base, int len, 
+                       void **err_address);
 externC void flash_dev_query(void *data);
 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
 externC int flash_lock(void *base, int len, void **err_address);
@@ -73,169 +153,46 @@ externC int flash_get_limits(void *base,
 externC int flash_get_block_info(int *block_size, int *blocks);
 externC bool flash_code_overlaps(void *start, void *end);
 externC char *flash_errmsg(int err);
+#endif // CYGSEM_IO_FLASH_LEGACY_API
 
-#define FLASH_ERR_OK              0x00  // No error - operation complete
-#define FLASH_ERR_INVALID         0x01  // Invalid FLASH address
-#define FLASH_ERR_ERASE           0x02  // Error trying to erase
-#define FLASH_ERR_LOCK            0x03  // Error trying to lock/unlock
-#define FLASH_ERR_PROGRAM         0x04  // Error trying to program
-#define FLASH_ERR_PROTOCOL        0x05  // Generic error
-#define FLASH_ERR_PROTECT         0x06  // Device/region is write-protected
-#define FLASH_ERR_NOT_INIT        0x07  // FLASH info not yet initialized
-#define FLASH_ERR_HWR             0x08  // Hardware (configuration?) problem
-#define FLASH_ERR_ERASE_SUSPEND   0x09  // Device is in erase suspend mode
-#define FLASH_ERR_PROGRAM_SUSPEND 0x0a  // Device is in in program suspend mode
-#define FLASH_ERR_DRV_VERIFY      0x0b  // Driver failed to verify data
-#define FLASH_ERR_DRV_TIMEOUT     0x0c  // Driver timed out waiting for device
-#define FLASH_ERR_DRV_WRONG_PART  0x0d  // Driver does not support device
-#define FLASH_ERR_LOW_VOLTAGE     0x0e  // Not enough juice to complete job
+#if defined(CYGSEM_IO_FLASH_LEGACY_API) || defined(CYGSEM_IO_FLASH_LEGACY_DEVICE_API)
+#define FLASH_ERR_OK              CYG_FLASH_ERR_OK              
+#define FLASH_ERR_INVALID         CYG_FLASH_ERR_INVALID         
+#define FLASH_ERR_ERASE           CYG_FLASH_ERR_ERASE           
+#define FLASH_ERR_LOCK            CYG_FLASH_ERR_LOCK            
+#define FLASH_ERR_PROGRAM         CYG_FLASH_ERR_PROGRAM         
+#define FLASH_ERR_PROTOCOL        CYG_FLASH_ERR_PROTOCOL        
+#define FLASH_ERR_PROTECT         CYG_FLASH_ERR_PROTECT         
+#define FLASH_ERR_NOT_INIT        CYG_FLASH_ERR_NOT_INIT        
+#define FLASH_ERR_HWR             CYG_FLASH_ERR_HWR             
+#define FLASH_ERR_ERASE_SUSPEND   CYG_FLASH_ERR_ERASE_SUSPEND   
+#define FLASH_ERR_PROGRAM_SUSPEND CYG_FLASH_ERR_PROGRAM_SUSPEND 
+#define FLASH_ERR_DRV_VERIFY      CYG_FLASH_ERR_DRV_VERIFY      
+#define FLASH_ERR_DRV_TIMEOUT     CYG_FLASH_ERR_DRV_TIMEOUT     
+#define FLASH_ERR_DRV_WRONG_PART  CYG_FLASH_ERR_DRV_WRONG_PART  
+#define FLASH_ERR_LOW_VOLTAGE     CYG_FLASH_ERR_LOW_VOLTAGE     
+#endif 
 
 #ifdef CYGPKG_IO_FLASH_BLOCK_DEVICE
 typedef struct {
     CYG_ADDRESS offset;
-    int len;
+    size_t len;
     int flasherr;
-    void **err_address;
+    cyg_flashaddr_t *err_address;
 } cyg_io_flash_getconfig_erase_t;
 
 typedef struct {
-    int dev_size;
+    size_t dev_size;
 } cyg_io_flash_getconfig_devsize_t;
 
 typedef struct {
     CYG_ADDRESS offset;
-    int block_size;
+    size_t block_size;
 } cyg_io_flash_getconfig_blocksize_t;
 #endif
 
 #ifdef _FLASH_PRIVATE_
-
-struct flash_info {
-    int   block_size;   // Assuming fixed size "blocks"
-    int   blocks;       // Number of blocks
-    int   buffer_size;  // Size of write buffer (only defined for some devices)
-    unsigned long block_mask;
-    void *start, *end;  // Address range
-    int   init;
-    _printf *pf;
-};
-
-externC struct flash_info flash_info;
-externC int  flash_hwr_init(void);
-externC int  flash_hwr_map_error(int err);
-
-// 
-// Some FLASH devices may require additional support, e.g. to turn on
-// appropriate voltage drivers, before any operation.
-//
-#ifdef  CYGIMP_FLASH_ENABLE
-#define FLASH_Enable CYGIMP_FLASH_ENABLE
-extern void CYGIMP_FLASH_ENABLE(void *, void *);
-#else
-#define FLASH_Enable(_start_, _end_)
-#endif
-#ifdef  CYGIMP_FLASH_DISABLE
-#define FLASH_Disable CYGIMP_FLASH_DISABLE
-extern void CYGIMP_FLASH_DISABLE(void *, void *);
-#else
-#define FLASH_Disable(_start_, _end_)
-#endif
-
-//
-// Some platforms have a DIP switch or jumper that tells the software that
-// the flash is write protected.
-//
-#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-externC cyg_bool plf_flash_query_soft_wp(void *addr, int len);
+#include <cyg/io/flash_priv.h>
 #endif
 
-//---------------------------------------------------------------------------
-// Execution of flash code must be done inside a
-// HAL_FLASH_CACHES_OFF/HAL_FLASH_CACHES_ON region - disabling the
-// cache on unified cache systems is necessary to prevent burst access
-// to the flash area being programmed. With Harvard style caches, only
-// the data cache needs to be disabled, but the instruction cache is
-// disabled for consistency.
-
-// Targets may provide alternative implementations for these macros in
-// the hal_cache.h (or var/plf) files.
-
-// The first part below is a generic, optimal implementation.  The
-// second part is the old implementation that has been tested to work
-// on some targets - but it is not be suitable for targets that would
-// do burst access to the flash (it does not disable the data cache).
-
-// Both implementations must be called with interrupts disabled.
-
-// NOTE: Do _not_ change any of the below macros without checking that
-//       the changed code still works on _all_ platforms that rely on these
-//       macros. There is no such thing as logical and correct when dealing
-//       with different cache and IO models, so _do not_ mess with this code
-//       unless you test it properly afterwards.
-
-#ifndef HAL_FLASH_CACHES_OFF
-
-// Some drivers have only been tested with the old macros below.
-#ifndef HAL_FLASH_CACHES_OLD_MACROS
-
-#ifdef HAL_CACHE_UNIFIED
-
-// Note: the ucache code has not been tested yet on any target.
-#define HAL_FLASH_CACHES_OFF(_d_, _i_)          \
-    CYG_MACRO_START                             \
-    _i_ = 0; /* avoids warning */               \
-    HAL_UCACHE_IS_ENABLED(_d_);                 \
-    HAL_UCACHE_SYNC();                          \
-    HAL_UCACHE_INVALIDATE_ALL();                \
-    HAL_UCACHE_DISABLE();                       \
-    CYG_MACRO_END
-
-#define HAL_FLASH_CACHES_ON(_d_, _i_)           \
-    CYG_MACRO_START                             \
-    if (_d_) HAL_UCACHE_ENABLE();               \
-    CYG_MACRO_END
-
-#else  // HAL_CACHE_UNIFIED
-
-#define HAL_FLASH_CACHES_OFF(_d_, _i_)          \
-    CYG_MACRO_START                             \
-    _i_ = 0; /* avoids warning */               \
-    HAL_DCACHE_IS_ENABLED(_d_);                 \
-    HAL_DCACHE_SYNC();                          \
-    HAL_DCACHE_INVALIDATE_ALL();                \
-    HAL_DCACHE_DISABLE();                       \
-    HAL_ICACHE_INVALIDATE_ALL();                \
-    CYG_MACRO_END
-
-#define HAL_FLASH_CACHES_ON(_d_, _i_)           \
-    CYG_MACRO_START                             \
-    if (_d_) HAL_DCACHE_ENABLE();               \
-    CYG_MACRO_END
-
-#endif // HAL_CACHE_UNIFIED
-
-#else  // HAL_FLASH_CACHES_OLD_MACROS
-
-// Note: This implementation is broken as it will always enable the i-cache
-//       even if it was not enabled before. It also doesn't work if the
-//       target uses burst access to flash since the d-cache is left enabled.
-//       However, this does not mean you can change this code! Leave it as
-//       is - if you want a different implementation, provide it in the
-//       arch/var/platform cache header file.
-
-#define HAL_FLASH_CACHES_OFF(_d_, _i_)          \
-    _d_ = 0; /* avoids warning */               \
-    _i_ = 0; /* avoids warning */               \
-    HAL_DCACHE_SYNC();                          \
-    HAL_ICACHE_DISABLE();
-
-#define HAL_FLASH_CACHES_ON(_d_, _i_)           \
-    HAL_ICACHE_ENABLE();
-
-#endif  // HAL_FLASH_CACHES_OLD_MACROS
-
-#endif  // HAL_FLASH_CACHES_OFF
-
-#endif  // _FLASH_PRIVATE_
-
 #endif  // _IO_FLASH_H_
new file mode 100644
--- /dev/null
+++ b/packages/io/flash/current/include/flash_priv.h
@@ -0,0 +1,251 @@
+//==========================================================================
+//
+//      flash.h
+//
+//      Flash programming - external interfaces
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+// copyright (C) 2004 Andrew Lunn
+//
+// 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas, Andrew Lunn
+// Date:         2000-07-14
+// Purpose:      
+// Description:  
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+#ifndef _IO_FLASH_PRIV_H_
+#define _IO_FLASH_PRIV_H_
+
+// Forward reference of the device structure
+struct cyg_flash_dev;
+
+// Structure of pointers to functions in the device driver
+struct cyg_flash_dev_funs {
+  int (*flash_init) (struct cyg_flash_dev *dev);
+  size_t (*flash_query) (struct cyg_flash_dev *dev, void * data, 
+                         const size_t len);
+  int (*flash_erase_block) (struct cyg_flash_dev *dev, 
+                            const cyg_flashaddr_t block_base);
+  int (*flash_program) (struct cyg_flash_dev *dev, 
+                        cyg_flashaddr_t base, 
+                        const void* data, const size_t len);
+  int (*flash_read) (struct cyg_flash_dev *dev, 
+                     const cyg_flashaddr_t base, 
+                     void* data, const size_t len);
+  int (*flash_hwr_map_error) (struct cyg_flash_dev *dev, int err);
+  int (*flash_block_lock) (struct cyg_flash_dev *dev, 
+                           const cyg_flashaddr_t block_base);
+  int (*flash_block_unlock) (struct cyg_flash_dev *dev, 
+                             const cyg_flashaddr_t block_base);
+};
+
+// Structure each device places in the HAL table
+struct cyg_flash_dev {
+  struct cyg_flash_dev_funs   *funs;           // Function pointers
+  cyg_flashaddr_t             start;           // First address
+  cyg_flashaddr_t             end;             // Last address
+  cyg_uint32                  num_block_infos; // Number of entries
+  cyg_block_info_t            *block_info;     // Info about one block size
+
+  void                        *priv;           // Devices private data
+  void                        *config;         // Configuration info
+
+// The following are only written to by the FLASH IO layer.
+  cyg_flash_printf            *pf;             // Pointer to diagnostic printf
+  bool                        init;            // Device has been initialised
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_t                 mutex;           // Mutex for thread safeness
+#endif
+  struct cyg_flash_dev        *next;           // Pointer to next device
+} CYG_HAL_TABLE_TYPE;
+
+#define CYG_FLASH_FUNS(funs,init,query,erase,prog,read,map,lock,unlock)\
+struct cyg_flash_dev_funs funs = \
+  {                                     \
+    init,                               \
+    query,                              \
+    erase,                              \
+    prog,                               \
+    read,                               \
+    map,                                \
+    lock,                               \
+    unlock                              \
+  };
+
+// We assume HAL tables are placed into RAM.
+#define CYG_FLASH_DRIVER(name, _funs, _config, _start, _priv_size)    \
+static char priv_ ## name [_priv_size];                               \
+struct cyg_flash_dev name CYG_HAL_TABLE_ENTRY(cyg_flashdev) = {       \
+   .funs = _funs,                                                     \
+   .config = _config,                                                 \
+   .priv = priv_ ## name,                                             \
+   .start = _start,                                                   \
+};
+
+#ifdef CYGSEM_IO_FLASH_LEGACY_DEVICE_API
+struct flash_info {
+  int   block_size;   // Assuming fixed size "blocks"
+  int   blocks;       // Number of blocks
+  int   buffer_size;  // Size of write buffer (only defined for some devices)
+  unsigned long block_mask;
+  void *start, *end;  // Address range
+  int   init;
+  cyg_flash_printf *pf;
+};
+
+externC struct flash_info flash_info;
+externC int  flash_hwr_init(void);
+externC int  flash_hwr_map_error(int err);
+externC void flash_dev_query(void *data);
+#endif // CYGSEM_IO_FLASH_LEGACY_DEVICE_API
+// 
+// Some FLASH devices may require additional support, e.g. to turn on
+// appropriate voltage drivers, before any operation.
+//
+#ifdef  CYGIMP_FLASH_ENABLE
+#define FLASH_Enable CYGIMP_FLASH_ENABLE
+extern void CYGIMP_FLASH_ENABLE(void *, void *);
+#else
+#define FLASH_Enable(_start_, _end_)
+#endif
+#ifdef  CYGIMP_FLASH_DISABLE
+#define FLASH_Disable CYGIMP_FLASH_DISABLE
+extern void CYGIMP_FLASH_DISABLE(void *, void *);
+#else
+#define FLASH_Disable(_start_, _end_)
+#endif
+
+//
+// Some platforms have a DIP switch or jumper that tells the software that
+// the flash is write protected.
+//
+#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
+externC cyg_bool plf_flash_query_soft_wp(void *addr, int len);
+#endif
+
+//---------------------------------------------------------------------------
+// Execution of flash code must be done inside a
+// HAL_FLASH_CACHES_OFF/HAL_FLASH_CACHES_ON region - disabling the
+// cache on unified cache systems is necessary to prevent burst access
+// to the flash area being programmed. With Harvard style caches, only
+// the data cache needs to be disabled, but the instruction cache is
+// disabled for consistency.
+
+// Targets may provide alternative implementations for these macros in
+// the hal_cache.h (or var/plf) files.
+
+// The first part below is a generic, optimal implementation.  The
+// second part is the old implementation that has been tested to work
+// on some targets - but it is not be suitable for targets that would
+// do burst access to the flash (it does not disable the data cache).
+
+// Both implementations must be called with interrupts disabled.
+
+// NOTE: Do _not_ change any of the below macros without checking that
+//       the changed code still works on _all_ platforms that rely on these
+//       macros. There is no such thing as logical and correct when dealing
+//       with different cache and IO models, so _do not_ mess with this code
+//       unless you test it properly afterwards.
+
+#ifndef HAL_FLASH_CACHES_OFF
+
+// Some drivers have only been tested with the old macros below.
+#ifndef HAL_FLASH_CACHES_OLD_MACROS
+
+#ifdef HAL_CACHE_UNIFIED
+
+// Note: the ucache code has not been tested yet on any target.
+#define HAL_FLASH_CACHES_OFF(_d_, _i_)          \
+    CYG_MACRO_START                             \
+    _i_ = 0; /* avoids warning */               \
+    HAL_UCACHE_IS_ENABLED(_d_);                 \
+    HAL_UCACHE_SYNC();                          \
+    HAL_UCACHE_INVALIDATE_ALL();                \
+    HAL_UCACHE_DISABLE();                       \
+    CYG_MACRO_END
+
+#define HAL_FLASH_CACHES_ON(_d_, _i_)           \
+    CYG_MACRO_START                             \
+    if (_d_) HAL_UCACHE_ENABLE();               \
+    CYG_MACRO_END
+
+#else  // HAL_CACHE_UNIFIED
+
+#define HAL_FLASH_CACHES_OFF(_d_, _i_)          \
+    CYG_MACRO_START                             \
+    _i_ = 0; /* avoids warning */               \
+    HAL_DCACHE_IS_ENABLED(_d_);                 \
+    HAL_DCACHE_SYNC();                          \
+    HAL_DCACHE_INVALIDATE_ALL();                \
+    HAL_DCACHE_DISABLE();                       \
+    HAL_ICACHE_INVALIDATE_ALL();                \
+    CYG_MACRO_END
+
+#define HAL_FLASH_CACHES_ON(_d_, _i_)           \
+    CYG_MACRO_START                             \
+    if (_d_) HAL_DCACHE_ENABLE();               \
+    CYG_MACRO_END
+
+#endif // HAL_CACHE_UNIFIED
+
+#else  // HAL_FLASH_CACHES_OLD_MACROS
+
+// Note: This implementation is broken as it will always enable the i-cache
+//       even if it was not enabled before. It also doesn't work if the
+//       target uses burst access to flash since the d-cache is left enabled.
+//       However, this does not mean you can change this code! Leave it as
+//       is - if you want a different implementation, provide it in the
+//       arch/var/platform cache header file.
+
+#define HAL_FLASH_CACHES_OFF(_d_, _i_)          \
+    _d_ = 0; /* avoids warning */               \
+    _i_ = 0; /* avoids warning */               \
+    HAL_DCACHE_SYNC();                          \
+    HAL_ICACHE_DISABLE();
+
+#define HAL_FLASH_CACHES_ON(_d_, _i_)           \
+    HAL_ICACHE_ENABLE();
+
+#endif  // HAL_FLASH_CACHES_OLD_MACROS
+
+#endif  // HAL_FLASH_CACHES_OFF
+
+#endif  // _IO_FLASH_PRIV_H_
--- a/packages/io/flash/current/src/flash.c
+++ b/packages/io/flash/current/src/flash.c
@@ -10,6 +10,7 @@
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2003 Gary Thomas
+// Copyright (C) 2004 Andrew Lunn
 //
 // 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
@@ -42,7 +43,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, Andrew Lunn
 // Date:         2000-07-26
 // Purpose:      
 // Description:  
@@ -53,503 +54,803 @@
 
 #include <pkgconf/system.h>
 #include <pkgconf/io_flash.h>
-
+#ifdef CYGPKG_KERNEL
+#include <cyg/kernel/kapi.h>
+#endif
 #include <cyg/hal/hal_arch.h>
 #include <cyg/hal/hal_intr.h>
 #include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_tables.h>
+#include <cyg/infra/cyg_ass.h>
 #include <string.h>
 
 #define  _FLASH_PRIVATE_
 #include <cyg/io/flash.h>
 
 // When this flag is set, do not actually jump to the relocated code.
-// This can be used for running the function in place (RAM startup only),
-// allowing calls to diag_printf() and similar.
+// This can be used for running the function in place (RAM startup
+// only), allowing calls to diag_printf() and similar.
 #undef RAM_FLASH_DEV_DEBUG
 #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
 # warning "Can only enable the flash debugging when configured for RAM startup"
 #endif
-
-struct flash_info flash_info;
-
-// These are the functions in the HW specific driver we need to call.
-typedef void code_fun(void*);
+#ifndef MIN
+#define MIN(x,y) ((x)<(y) ? (x) : (y))
+#endif
 
-externC code_fun flash_query;
-externC code_fun flash_erase_block;
-externC code_fun flash_program_buf;
-externC code_fun flash_read_buf;
-externC code_fun flash_lock_block;
-externC code_fun flash_unlock_block;
+// Has the FLASH IO library been initialise?
+static bool init = false;
+// We have a linked list of flash drivers. This is the head of the
+// list
+static struct cyg_flash_dev *flash_head = NULL;
+
+// This array contains entries for all flash devices that are
+// installed in the system.
+__externC struct cyg_flash_dev cyg_flashdevtab[];
+CYG_HAL_TABLE_BEGIN(cyg_flashdevtab, cyg_flashdev);
+
+// end of the flashdev table
+__externC struct cyg_flash_dev cyg_flashdevtab_end;
+CYG_HAL_TABLE_END(cyg_flashdevtab_end, cyg_flashdev);
 
-int
-flash_init(_printf *pf)
+// Sort the linked list into ascending order of flash address. Use a
+// primitive ripple sort, but since we don't expect to have many
+// devices this should be OK.
+static void flash_sort(void) 
 {
-    int err;
+  bool moved;
+  struct cyg_flash_dev *dev, **previous_next;
+  
+  // If there is zero or one device, short cut
+  if (flash_head == NULL || flash_head->next == NULL)
+    return;
+  
+  do {
+    moved=false;
+    for (dev=flash_head, previous_next=&flash_head; 
+         dev->next; 
+         previous_next = &dev->next, dev=dev->next ){
+      if (dev->start > dev->next->start) {
+        *previous_next=dev->next;
+        dev->next = (*previous_next)->next;
+        (*previous_next)->next = dev;
+        moved=true;          
+        break;
+      }
+    }
+  } while (moved);
+}
 
-    if (flash_info.init) return FLASH_ERR_OK;
-    flash_info.pf = pf; // Do this before calling into the driver
-    if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
-        return err;
-    }
-    flash_info.block_mask = ~(flash_info.block_size-1);
-    flash_info.init = 1;
-    return FLASH_ERR_OK;
+// Walk the linked list and see if there are any overlaps in the
+// addresses the devices claim to use using.
+static bool flash_check_overlap(void) 
+{
+  struct cyg_flash_dev *dev;
+  
+  // If there is zero or one device, short cut
+  if (flash_head == NULL || flash_head->next == NULL)
+    return false;
+
+  for (dev=flash_head; dev->next; dev=dev->next){
+    if (dev->end >= dev->next->start)
+      return true;
+  }
+  return false;
 }
 
-// Use this function to make function pointers anonymous - forcing the
-// compiler to use jumps instead of branches when calling driver
-// services.
-static void* __anonymizer(void* p)
+// Initialise all registered device. Any device that fails to
+// initialise we leave dev->init as false. Then sort the devices into
+// ascending order of address and put them into a linked list. Lastly
+// check if we have any overlap of the addresses.
+__externC int 
+cyg_flash_init(cyg_flash_printf *pf) 
 {
-  return p;
+  int err;
+  struct cyg_flash_dev * dev;
+  
+  if (init) return CYG_FLASH_ERR_OK;
+  init = true;
+  
+  for (dev = &cyg_flashdevtab[0]; dev != &cyg_flashdevtab_end; dev++) {
+    dev->pf = pf;
+#ifdef CYGPKG_KERNEL
+    cyg_mutex_init(&dev->mutex);
+#endif
+    
+    err = dev->funs->flash_init(dev);
+    if (err != CYG_FLASH_ERR_OK) {
+      continue;
+    }
+    CYG_ASSERT(dev->funs, "No flash functions");
+    CYG_ASSERT(dev->num_block_infos, "No number of block infoss");
+    CYG_ASSERT(dev->block_info, "No block infos");
+    CYG_ASSERT(!(((cyg_flashaddr_t)dev->block_info >= dev->start) && 
+                 ((cyg_flashaddr_t)dev->block_info < dev->end)),
+               "Block info is in the flash");
+    CYG_ASSERT(dev->funs->flash_erase_block, "No erase function");
+    CYG_ASSERT(dev->funs->flash_program, "No program function");
+    CYG_ASSERT(dev->funs->flash_hwr_map_error, "No hwr map error function");
+
+    dev->init = true;
+    dev->next = flash_head;
+    flash_head = dev;
+  }
+  
+  flash_sort();
+
+  if (flash_check_overlap()) {
+    return CYG_FLASH_ERR_INVALID;
+  }
+  return CYG_FLASH_ERR_OK;
 }
 
-// FIXME: Want to change all drivers to use this function. But it may
-// make sense to wait till device structure pointer arguments get
-// added as well.
-void
-flash_dev_query(void* data)
+// Is the address within one of the flash drivers?
+__externC int
+cyg_flash_verify_addr(const cyg_flashaddr_t address)
 {
-    typedef void code_fun(void*);
-    code_fun *_flash_query;
-    int d_cache, i_cache;
-
-    _flash_query = (code_fun*) __anonymizer(&flash_query);
-
-    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-    (*_flash_query)(data);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+  struct cyg_flash_dev * dev;
+  
+  if (!init) return CYG_FLASH_ERR_NOT_INIT;
+  
+  for (dev = flash_head; dev; dev=dev->next) {
+    if ((dev->start <= address) && (dev->end > address))
+      return CYG_FLASH_ERR_OK;
+  }
+  return CYG_FLASH_ERR_INVALID;
 }
 
-int
-flash_verify_addr(void *target)
+// See if a range of FLASH addresses overlaps currently running code
+__externC bool cyg_flash_code_overlaps(const cyg_flashaddr_t start, 
+                                       const cyg_flashaddr_t end)
 {
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-    if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
-        ((CYG_ADDRESS)target <= ( ((CYG_ADDRESS)flash_info.end) - 1) )) {
-        return FLASH_ERR_OK;
-    } else {
-        return FLASH_ERR_INVALID;
-    }
+  extern char _stext[], _etext[];
+  
+  return ((((unsigned long)&_stext >= (unsigned long)start) &&
+           ((unsigned long)&_stext < (unsigned long)end)) ||
+          (((unsigned long)&_etext >= (unsigned long)start) &&
+           ((unsigned long)&_etext < (unsigned long)end)));
 }
 
-int
-flash_get_limits(void *target, void **start, void **end)
+// Get the start and end address of the first driver
+__externC int
+cyg_flash_get_limits(cyg_flashaddr_t *start, cyg_flashaddr_t *end)
 {
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
+    if (!init) {
+        return CYG_FLASH_ERR_NOT_INIT;
     }
-    *start = flash_info.start;
-    *end = flash_info.end;
-    return FLASH_ERR_OK;
+    if (flash_head) {
+      *start = flash_head->start;
+      *end = flash_head->end;
+      return CYG_FLASH_ERR_OK;
+    }
+    return CYG_FLASH_ERR_INVALID;
 }
 
-int
-flash_get_block_info(int *block_size, int *blocks)
+// Get the block size and number of blocks for the first driver. For
+// devices with boot blocks, consolidate the boot blocks into the
+// figure.
+__externC int
+cyg_flash_get_block_info(size_t *block_size, cyg_uint32 *blocks)
 {
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
+  size_t biggest_size=0;
+  cyg_uint32 i;
+  
+  
+  if (!init) {
+    return CYG_FLASH_ERR_NOT_INIT;
+  }
+  if (!flash_head) return CYG_FLASH_ERR_INVALID;
+
+  // Find the biggest size of blocks
+  for (i=0; i < flash_head->num_block_infos; i++) {
+    if (flash_head->block_info[i].block_size > biggest_size) {
+      biggest_size = flash_head->block_info[i].block_size;
     }
-    *block_size = flash_info.block_size;
-    *blocks = flash_info.blocks;
-    return FLASH_ERR_OK;
+  }
+  
+  // Calculate the number of biggest size blocks
+  *block_size = biggest_size;
+  *blocks = 0;
+  for (i=0; i < flash_head->num_block_infos; i++) {
+    *blocks += (flash_head->block_info[i].block_size *
+                flash_head->block_info[i].blocks) /
+      biggest_size;
+  }
+  return CYG_FLASH_ERR_OK;
+}
+
+// Return information about the Nth driver
+__externC int
+cyg_flash_get_info(cyg_uint32 Nth, cyg_flash_info_t * info)
+{
+  struct cyg_flash_dev * dev;
+  
+  if (!init) return CYG_FLASH_ERR_NOT_INIT;
+  
+  for (dev = flash_head; dev && Nth; dev=dev->next, Nth--)
+    ;
+  if (dev && !Nth) {
+    info->start = dev->start;
+    info->end = dev->end;
+    info->num_block_infos = dev->num_block_infos;
+    info->block_info = dev->block_info;
+    return CYG_FLASH_ERR_OK;
+  }
+  return CYG_FLASH_ERR_INVALID;
 }
 
-int
-flash_erase(void *addr, int len, void **err_addr)
+// Return information about the flash at the given address
+__externC int
+cyg_flash_get_info_addr(cyg_flashaddr_t flash_base, cyg_flash_info_t * info)
 {
-    unsigned short *block, *end_addr;
-    int stat = 0;
-    typedef int code_fun(unsigned short *, unsigned int);
-    code_fun *_flash_erase_block;
-    int d_cache, i_cache;
-
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
+  struct cyg_flash_dev *dev;
+  
+  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)) {
+    info->start = dev->start;
+    info->end = dev->end;
+    info->num_block_infos = dev->num_block_infos;
+    info->block_info = dev->block_info;
+    return CYG_FLASH_ERR_OK;
     }
-
-#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-    if (plf_flash_query_soft_wp(addr,len))
-        return FLASH_ERR_PROTECT;
-#endif
-
-     _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block);
-
-    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
-    end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
+  }
+  return CYG_FLASH_ERR_INVALID;
+}
 
-    /* Check to see if end_addr overflowed */
-    if( (end_addr < block) && (len > 0) ){
-        end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
+#ifdef CYGPKG_KERNEL
+//Lock the mutex's for a range of addresses
+__externC int
+cyg_flash_mutex_lock(const cyg_flashaddr_t from, const size_t len) 
+{
+  struct cyg_flash_dev * dev;
+  int err;
+  
+  if (!init) return CYG_FLASH_ERR_NOT_INIT;
+  
+  for (dev = flash_head; dev ; dev=dev->next) {
+    if ((dev->start <= from) && ( dev->end > from)) {
+      cyg_mutex_lock(&dev->mutex);
+      if (dev->end > from+len) {
+        return CYG_FLASH_ERR_OK;
+      } else {                                     // Check off by one?
+        //The region is bigger than this driver. Recurse
+        err = cyg_flash_mutex_lock(dev->end+1, (len - (dev->end - from)));
+        if (err != CYG_FLASH_ERR_OK) {
+          // Something went wrong, unlock what we just locked
+          cyg_mutex_unlock(&dev->mutex);
+        }
+        return err;
+      }
     }
-
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Erase from %p-%p: ", (void*)block, (void*)end_addr);
-#endif
+  }
+  return CYG_FLASH_ERR_INVALID;
+}
 
-    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-    FLASH_Enable(block, end_addr);
-    while (block < end_addr) {
-        // Supply the blocksize for a gross check for erase success
-        unsigned short *tmp_block;
-#if !defined(CYGSEM_IO_FLASH_READ_INDIRECT)
-        int i;
-        unsigned char *dp;
-        bool erased = true;
-
-        dp = (unsigned char *)block;
-        for (i = 0;  i < flash_info.block_size;  i++) {
-            if (*dp++ != (unsigned char)0xFF) {
-                erased = false;
-                break;
-            }
-        }
-#else
-        bool erased = false;
+//Unlock the mutex's for a range of addresses
+__externC int
+cyg_flash_mutex_unlock(const cyg_flashaddr_t from, const size_t len) 
+{
+  struct cyg_flash_dev * dev;
+  int err;
+  
+  if (!init) return CYG_FLASH_ERR_NOT_INIT;
+  
+  for (dev = flash_head; dev ; dev=dev->next) {
+    if ((dev->start <= from) && ( dev->end > from)) {
+      cyg_mutex_unlock(&dev->mutex);
+      if (dev->end > from+len) {
+        return CYG_FLASH_ERR_OK;
+      } else {                                     // Check off by one?
+        //The region is bigger than this driver. Recurse
+        err = cyg_flash_mutex_unlock(dev->end+1, (len - (dev->end - from)));
+        return err;
+      }
+    }
+  }
+  return CYG_FLASH_ERR_INVALID;
+}
 #endif
 
-        if (!erased) {
-            stat = (*_flash_erase_block)(block, flash_info.block_size);
-            stat = flash_hwr_map_error(stat);
-        }
-        if (stat) {
-            *err_addr = (void *)block;
-            break;
-        }
+// Return the size of the block which is at the given address
+static size_t 
+flash_block_size(struct cyg_flash_dev *dev, const cyg_flashaddr_t addr)
+{
+  int i;
+  size_t offset;
+  
+  
+  CYG_ASSERT((addr >= dev->start) && (addr <= dev->end), "Not inside device");
+  
+  offset = addr - dev->start;
+  for (i=0; i < dev->num_block_infos; i++) {
+    if (offset < (dev->block_info[i].blocks * dev->block_info[i].block_size))
+      return dev->block_info[i].block_size;
+    offset = offset - 
+      (dev->block_info[i].blocks * dev->block_info[i].block_size);
+  }
+  CYG_FAIL("Programming error");
+  return 0;
+}
+
+// Return the size of the block which is at the given address
+__externC size_t
+cyg_flash_block_size(const cyg_flashaddr_t flash_base) 
+{
+  struct cyg_flash_dev * dev;
+
+  if (!init) return CYG_FLASH_ERR_NOT_INIT;
+
+  for (dev = flash_head; 
+       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev=dev->next)
+    ;
+  if (!dev) return CYG_FLASH_ERR_INVALID;
+  
+  return flash_block_size(dev, flash_base);
+}
+
 
-        // Check to see if block will overflow
-        tmp_block = block + flash_info.block_size / sizeof(*block);
-        if(tmp_block < block){
-            // If block address overflows, set block value to end on this loop
-            block = end_addr;
-        }
-        else{
-            block = tmp_block;
-        }
+__externC int 
+cyg_flash_erase(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;
+  
+#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_size = flash_block_size(dev, addr);
+  block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1));
+  
 #ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
+  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) {
+    int i;
+    unsigned char *dp;
+    bool erased = true;
+
+    // If there is a read function it probably means the flash
+    // cannot be read directly.
+    if (!dev->funs->flash_read) {
+      dp = (unsigned char *)block;
+      for (i = 0;  i < block_size;  i++) {
+        if (*dp++ != (unsigned char)0xFF) {
+          erased = false;
+          break;
+        }
+      }
+    } else {
+      erased=false;
+    }
+    if (!erased) {
+      stat = dev->funs->flash_erase_block(dev,block);
+      stat = dev->funs->flash_hwr_map_error(dev,stat);
     }
-    FLASH_Disable(block, end_addr);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = block;
+      break;
+    }
+    block += flash_block_size(dev, block);
+#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
-    (*flash_info.pf)("\n");
+  dev->pf("\n");
+#endif
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_unlock(&dev->mutex);
 #endif
-    return (stat);
+  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_erase(dev->end+1, 
+                           len - (dev->end - flash_base) - 1,
+                           err_address);
+  }
+  return CYG_FLASH_ERR_OK;
 }
 
-int
-flash_program(void *_addr, void *_data, int len, void **err_addr)
+__externC int 
+cyg_flash_program(const cyg_flashaddr_t flash_base, 
+                  void *ram_base, 
+                  const size_t len, 
+                  cyg_flashaddr_t *err_address)
 {
-    int stat = 0;
-    int size;
-    typedef int code_fun(void *, void *, int, unsigned long, int);
-    code_fun *_flash_program_buf;
-    unsigned char *addr = (unsigned char *)_addr;
-    unsigned char *data = (unsigned char *)_data;
-    CYG_ADDRESS tmp;
-    int d_cache, i_cache;
-
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-
+  struct cyg_flash_dev * dev;
+  cyg_flashaddr_t addr, end_addr;
+  unsigned char * ram = ram_base;
+  size_t block_size, size, length, offset;
+  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 FLASH_ERR_PROTECT;
+  if (plf_flash_query_soft_wp(addr,len))
+    return CYG_FLASH_ERR_PROTECT;
 #endif
-
-    _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf);
-
+  
+  for (dev = flash_head; 
+       dev && !((dev->start <= flash_base) && ( dev->end > flash_base));
+       dev=dev->next)
+    ;
+  if (!dev) 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;
+  }
+  length = end_addr - addr + 1;
+  
 #ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data, 
-                     (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
+  dev->pf("... Program from %p-%p to %p: ", ram_base, 
+          ((CYG_ADDRESS)ram_base)+length, addr);
 #endif
-
-    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-    FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
-    while (len > 0) {
-        size = len;
-        if (size > flash_info.block_size) size = flash_info.block_size;
-
-        tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
-        if (tmp) {
-                tmp = flash_info.block_size - tmp;
-                if (size>tmp) size = tmp;
-
-        }
-
-        stat = (*_flash_program_buf)(addr, data, size, 
-                                     flash_info.block_mask, flash_info.buffer_size);
-        stat = flash_hwr_map_error(stat);
+  
+  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;
+    
+    // Writing from the middle of a block?
+    offset = (size_t)addr & (block_size-1);
+    if (offset)
+      size = MIN(block_size - offset, size);
+    stat = dev->funs->flash_program(dev, addr, ram, size);
+    stat = dev->funs->flash_hwr_map_error(dev,stat);
 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
-        if (0 == stat) // Claims to be OK
-            if (memcmp(addr, data, size) != 0) {                
-                stat = 0x0BAD;
+    if (CYG_FLASH_ERR_OK == stat) // Claims to be OK
+      if (!dev->funs->flash_read && memcmp((void *)addr, ram, size) != 0) {                
+        stat = CYG_FLASH_ERR_DRV_VERIFY;
 #ifdef CYGSEM_IO_FLASH_CHATTER
-                (*flash_info.pf)("V");
+        dev->pf("V");
 #endif
-            }
+      }
 #endif
-        if (stat) {
-            *err_addr = (void *)addr;
-            break;
-        }
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = addr;
+      break;
+    }
 #ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
+    dev->pf(".");
 #endif
-        len -= size;
-        addr += size/sizeof(*addr);
-        data += size/sizeof(*data);
-    }
-    FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    length -= size;
+    addr += size;
+    ram += size;
+  }
+  FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
+  HAL_FLASH_CACHES_ON(d_cache, i_cache);
 #ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
+    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) {
+    return cyg_flash_program(dev->end+1, ram, 
+                             len - (dev->end - flash_base) - 1,
+                             err_address);
+  }
+  return CYG_FLASH_ERR_OK;
 }
 
-int
-flash_read(void *_addr, void *_data, int len, void **err_addr)
+__externC int 
+cyg_flash_read(cyg_flashaddr_t flash_base, 
+               const void *ram_base, 
+               const size_t len, 
+               cyg_flashaddr_t *err_address)
 {
-#ifdef CYGSEM_IO_FLASH_READ_INDIRECT
-    int stat = 0;
-    int size;
-    typedef int code_fun(void *, void *, int, unsigned long, int);
-    code_fun *_flash_read_buf;
-    unsigned char *addr = (unsigned char *)_addr;
-    unsigned char *data = (unsigned char *)_data;
-    CYG_ADDRESS tmp;
-    int d_cache, i_cache;
-
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-
-    _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf);
-
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Read from %p-%p at %p: ", (void*)data, 
-                     (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
-#endif
-
-    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-    FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
-    while (len > 0) {
-        size = len;
-        if (size > flash_info.block_size) size = flash_info.block_size;
-
-        tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
-        if (tmp) {
-                tmp = flash_info.block_size - tmp;
-                if (size>tmp) size = tmp;
-
-        }
+  struct cyg_flash_dev * dev;
+  cyg_flashaddr_t addr, end_addr;
+  unsigned char * ram = (unsigned char *)ram_base;
+  size_t block_size, size, length, 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->next)
+    ;
+  if (!dev) return CYG_FLASH_ERR_INVALID;
 
-        stat = (*_flash_read_buf)(addr, data, size, 
-                                     flash_info.block_mask, flash_info.buffer_size);
-        stat = flash_hwr_map_error(stat);
-#ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM_
-        if (0 == stat) // Claims to be OK
-            if (memcmp(addr, data, size) != 0) {                
-                stat = 0x0BAD;
+#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;
+  }
+  length = end_addr - addr + 1;
+  
 #ifdef CYGSEM_IO_FLASH_CHATTER
-                (*flash_info.pf)("V");
-#endif
-            }
-#endif
-        if (stat) {
-            *err_addr = (void *)addr;
-            break;
-        }
-#ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
+  dev->pf("... Read from %p-%p to %p: ", addr, addr+len, ram_base);
 #endif
-        len -= size;
-        addr += size/sizeof(*addr);
-        data += size/sizeof(*data);
+  
+  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;
+    
+    // Reading from the middle of a block?
+    offset = (size_t)addr & (block_size-1);
+    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_hwr_map_error(dev,stat);
+    } else {
+      memcpy(ram, (void *)addr, size);
+      stat = CYG_FLASH_ERR_OK;
     }
-    FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = addr;
+      break;
+    }
 #ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
+    dev->pf(".");
 #endif
+    length -= size;
+    addr += size;
+    ram += size;
+  }
+  FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
+  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);
-#else // CYGSEM_IO_FLASH_READ_INDIRECT
-    // Direct access to FLASH memory is possible - just move the requested bytes
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-    memcpy(_data, _addr, len);
-    return FLASH_ERR_OK;
-#endif
+  }
+  if ( flash_base + len - 1 > dev->end) {
+    return cyg_flash_read(dev->end+1, ram,
+                          len - (dev->end - flash_base) - 1,
+                          err_address);
+  }
+  return CYG_FLASH_ERR_OK;
 }
 
 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
-
-int
-flash_lock(void *addr, int len, void **err_addr)
+__externC int 
+cyg_flash_lock(const cyg_flashaddr_t flash_base, 
+               const size_t len, 
+               cyg_flashaddr_t *err_address)
 {
-    unsigned short *block, *end_addr;
-    int stat = 0;
-    typedef int code_fun(unsigned short *);
-    code_fun *_flash_lock_block;
-    int d_cache, i_cache;
-
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-
+  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 FLASH_ERR_PROTECT;
+  if (plf_flash_query_soft_wp(addr,len))
+    return CYG_FLASH_ERR_PROTECT;
 #endif
-
-    _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block);
+  
+  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_lock) return CYG_FLASH_ERR_INVALID;
 
-    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
-    end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
-
-    /* Check to see if end_addr overflowed */
-    if( (end_addr < block) && (len > 0) ){
-        end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
-    }
-
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Lock from %p-%p: ", block, end_addr);
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_lock(&dev->mutex);
 #endif
-
-    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-    FLASH_Enable(block, end_addr);
-    while (block < end_addr) {
-        unsigned short *tmp_block;
-        stat = (*_flash_lock_block)(block);
-        stat = flash_hwr_map_error(stat);
-        if (stat) {
-            *err_addr = (void *)block;
-            break;
-        }
-
-        // Check to see if block will overflow
-        tmp_block = block + flash_info.block_size / sizeof(*block);
-        if(tmp_block < block){
-            // If block address overflows, set block value to end on this loop
-            block = end_addr;
-        }
-        else{
-            block = tmp_block;
-        }
+  addr = flash_base;
+  end_addr = flash_base + len - 1;
+  if (end_addr > dev->end) {
+    end_addr = dev->end;
+  }
+  
+  block_size = flash_block_size(dev, addr);
+  block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1));
+  
 #ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
+  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) {
+    stat = dev->funs->flash_block_lock(dev,block);
+    stat = dev->funs->flash_hwr_map_error(dev,stat);
+    
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = (void *)block;
+      break;
     }
-    FLASH_Disable(block, end_addr);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    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
-    (*flash_info.pf)("\n");
+  dev->pf("\n");
+#endif
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_unlock(&dev->mutex);
 #endif
-    return (stat);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return stat;
+  }
+  
+  if (flash_base + len - 1 > dev->end) {        // Off by one?
+    // The region to erase if bigger than this driver handles. Recurse
+    return cyg_flash_lock(dev->end+1, 
+                          len - (dev->end - flash_base) - 1,
+                          err_address);
+  }
+  return CYG_FLASH_ERR_OK;
 }
 
-int
-flash_unlock(void *addr, int len, void **err_addr)
+__externC int 
+cyg_flash_unlock(const cyg_flashaddr_t flash_base, 
+                 const size_t len, 
+                 cyg_flashaddr_t *err_address)
 {
-    unsigned short *block, *end_addr;
-    int stat = 0;
-    typedef int code_fun(unsigned short *, int, int);
-    code_fun *_flash_unlock_block;
-    int d_cache, i_cache;
-
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-
+  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 FLASH_ERR_PROTECT;
+  if (plf_flash_query_soft_wp(addr,len))
+    return CYG_FLASH_ERR_PROTECT;
 #endif
-
-    _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block);
-
-    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
-    end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
-
-    /* Check to see if end_addr overflowed */
-    if( (end_addr < block) && (len > 0) ){
-        end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
-    }
-
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Unlock from %p-%p: ", block, end_addr);
+  
+  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_lock) return CYG_FLASH_ERR_INVALID;
+  
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_lock(&dev->mutex);
 #endif
-
-    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
-    FLASH_Enable(block, end_addr);
-    while (block < end_addr) {
-        unsigned short *tmp_block;
-        stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
-        stat = flash_hwr_map_error(stat);
-        if (stat) {
-            *err_addr = (void *)block;
-            break;
-        }
-
-        tmp_block = block + flash_info.block_size / sizeof(*block);
-        if(tmp_block < block){
-            // If block address overflows, set block value to end on this loop
-            block = end_addr;
-        }
-        else{
-            block = tmp_block;
-        }
+  addr = flash_base;
+  end_addr = flash_base + len - 1;
+  if (end_addr > dev->end) {
+    end_addr = dev->end;
+  }
+  
+  block_size = flash_block_size(dev, addr);
+  block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1));
+  
 #ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
+  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 = (void *)block;
+      break;
     }
-    FLASH_Disable(block, end_addr);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+    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
-    (*flash_info.pf)("\n");
+  dev->pf("\n");
+#endif
+#ifdef CYGPKG_KERNEL
+  cyg_mutex_unlock(&dev->mutex);
 #endif
-    return (stat);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return stat;
+  }
+  
+  if (flash_base + len - 1 > dev->end) {        // Off by one?
+    // The region to erase if bigger than this driver handles. Recurse
+    return cyg_flash_lock(dev->end+1, 
+                          len - (dev->end - flash_base) - 1,
+                          err_address);
+  }
+  return CYG_FLASH_ERR_OK;
 }
 #endif
 
-char *
-flash_errmsg(int err)
+const char *
+cyg_flash_errmsg(const int err)
 {
     switch (err) {
-    case FLASH_ERR_OK:
+    case CYG_FLASH_ERR_OK:
         return "No error - operation complete";
-    case FLASH_ERR_ERASE_SUSPEND:
+    case CYG_FLASH_ERR_ERASE_SUSPEND:
         return "Device is in erase suspend state";
-    case FLASH_ERR_PROGRAM_SUSPEND:
+    case CYG_FLASH_ERR_PROGRAM_SUSPEND:
         return "Device is in program suspend state";
-    case FLASH_ERR_INVALID:
+    case CYG_FLASH_ERR_INVALID:
         return "Invalid FLASH address";
-    case FLASH_ERR_ERASE:
+    case CYG_FLASH_ERR_ERASE:
         return "Error trying to erase";
-    case FLASH_ERR_LOCK:
+    case CYG_FLASH_ERR_LOCK:
         return "Error trying to lock/unlock";
-    case FLASH_ERR_PROGRAM:
+    case CYG_FLASH_ERR_PROGRAM:
         return "Error trying to program";
-    case FLASH_ERR_PROTOCOL:
+    case CYG_FLASH_ERR_PROTOCOL:
         return "Generic error";
-    case FLASH_ERR_PROTECT:
+    case CYG_FLASH_ERR_PROTECT:
         return "Device/region is write-protected";
-    case FLASH_ERR_NOT_INIT:
+    case CYG_FLASH_ERR_NOT_INIT:
         return "FLASH sub-system not initialized";
-    case FLASH_ERR_DRV_VERIFY:
+    case CYG_FLASH_ERR_DRV_VERIFY:
         return "Data verify failed after operation";
-    case FLASH_ERR_DRV_TIMEOUT:
+    case CYG_FLASH_ERR_DRV_TIMEOUT:
         return "Driver timed out waiting for device";
-    case FLASH_ERR_DRV_WRONG_PART:
+    case CYG_FLASH_ERR_DRV_WRONG_PART:
         return "Driver does not support device";
-    case FLASH_ERR_LOW_VOLTAGE:
+    case CYG_FLASH_ERR_LOW_VOLTAGE:
         return "Device reports low voltage";
     default:
         return "Unknown error";
--- a/packages/io/flash/current/src/flashiodev.c
+++ b/packages/io/flash/current/src/flashiodev.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
 //
 // 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
@@ -41,7 +42,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    jlarmour
-// Contributors: woehler
+// Contributors: woehler, Andrew Lunn
 // Date:         2002-01-16
 // Purpose:      
 // Description:  
@@ -62,110 +63,121 @@
 #include <cyg/hal/hal_if.h>
 
 #define MIN(x,y) ((x)<(y) ? (x) : (y))
+#define MAX(x,y) ((x)>(y) ? (x) : (y))
 
 struct flashiodev_priv_t{
-	char *start;
-	char *end;
+  cyg_flashaddr_t start;
+  cyg_flashaddr_t end;
+  cyg_bool        use_fis;
+  cyg_bool        use_absolute;
+  cyg_bool        use_offset;
+  char *          fis_name;
+  cyg_uint32      block_size;
 };
 
-static struct flashiodev_priv_t flashiodev_priv[1];
-
 static int dummy_printf( const char *fmt, ... ) {return 0;}
 
 static bool
 flashiodev_init( struct cyg_devtab_entry *tab )
 {
-    struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
-    int stat = flash_init( &dummy_printf );
-    if ( stat == 0 ) {
-#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1
-        CYG_ADDRESS		flash_base;
-        unsigned long	size;
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
+  cyg_flash_info_t info;
+  cyg_uint32 i;
+  
+  int stat = cyg_flash_init( &dummy_printf );
+  if ( stat == 0 ) {
+    if (dev->use_fis) {
+      CYG_ADDRESS	flash_base;
+      unsigned long	size;
+    
+      if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, 
+                                      dev->fis_name,
+                                      &flash_base))
+        return false;
+      if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, 
+                                      dev->fis_name,
+                                      &size))
+        return false;
+    
+      dev->start = flash_base;
+      dev->end = flash_base + size;
+    }
+    if (dev->use_offset) {
+      // dev->start the contain the offset to the beginning of the block
+      // dev->end is the length of the block
+      cyg_flashaddr_t start, end;
+      cyg_flash_get_limits(&start, &end);
+      dev->start = dev->start + start;
+      dev->end = dev->start + dev->end;
+    }
+    if (dev->use_absolute) {
+      // dev->start is the absolute address of the start
+      // dev->end is the length;
+      dev->end = dev->start + dev->end;
+    }
 
-        if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, 
-                                        CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1,
-                                        &flash_base))
-            return false;
-        if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, 
-                                        CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1,
-                                        &size))
-            return false;
-			
-        dev->start = (char *)flash_base;
-        dev->end = (char *)flash_base + size;
-#else
-        dev->start = (char *)flash_info.start + CYGNUM_IO_FLASH_BLOCK_OFFSET_1;
-        dev->end = (char *)flash_info.start + CYGNUM_IO_FLASH_BLOCK_OFFSET_1 + 
-            CYGNUM_IO_FLASH_BLOCK_LENGTH_1;
-#endif
-        return true;
-    } else
-        return false;
+    stat = cyg_flash_get_info_addr(dev->start, &info);
+    if (stat != CYG_FLASH_ERR_OK) {
+      return false;
+    }
+    dev->block_size = 0;
+    for (i=0; i < info.num_block_infos; i++){
+      dev->block_size = MAX(dev->block_size, info.block_info[i].block_size);
+    }
+    
+    return true;
+  } else
+    return false;
 } // flashiodev_init()
 
-#if 0
-static Cyg_ErrNo
-flashiodev_lookup( struct cyg_devtab_entry **tab, 
-                   struct cyg_devtab_entry *sub_tab,
-                   const char *name)
-{   
-} // flashiodev_lookup()
-#endif
-
 static Cyg_ErrNo
 flashiodev_bread( cyg_io_handle_t handle, void *buf, cyg_uint32 *len,
                   cyg_uint32 pos)
 {
-	struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
-	struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
-
-	char *startpos = dev->start + pos;
-        void *erraddr;
-        Cyg_ErrNo err = ENOERR;
-        
-
+  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
+  
+  cyg_flashaddr_t startpos = dev->start + pos;
+  Cyg_ErrNo err;
+  
+  
 #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
-    char *endpos = startpos + *len - 1;
-    char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1);
-    if ( startpos < dev->start )
-        return -EINVAL;
-    if ( endpos > flashend )
-        return -EINVAL;
+  cyg_flashaddr_t endpos = startpos + *len - 1;
+  if ( startpos < dev->start )
+    return -EINVAL;
+  if ( endpos > dev->end )
+    return -EINVAL;
 #endif
-    
-    err = flash_read( startpos,
-                      (void *)buf, *len, &erraddr );
-
-    if ( err )
-        err = -EIO; // just something sane
-    return err;
+  
+  err = cyg_flash_read( startpos,(void *)buf, *len, NULL );
+  
+  if ( err != CYG_FLASH_ERR_OK )
+    err = -EIO; // just something sane
+  return err;
 } // flashiodev_bread()
 
 static Cyg_ErrNo
 flashiodev_bwrite( cyg_io_handle_t handle, const void *buf, cyg_uint32 *len,
                    cyg_uint32 pos )
-{   
-	struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
-	struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
-
-    Cyg_ErrNo err = ENOERR;
-    void *erraddr;
-    char *startpos = dev->start + pos;
-
+{
+  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
+  
+  Cyg_ErrNo err;
+  cyg_flashaddr_t startpos = dev->start + pos;
+  
 #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
-    char *endpos = startpos + *len - 1;
-    char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1);
-    if ( startpos < dev->start )
-        return -EINVAL;
-    if ( endpos > flashend )
-        return -EINVAL;
+  cyg_flashaddr_t endpos = startpos + *len - 1;
+  if ( startpos < dev->start )
+    return -EINVAL;
+  if ( endpos > dev->end )
+    return -EINVAL;
 #endif
-    err = flash_program( startpos, 
-                         (void *)buf, *len, &erraddr );
-
-    if ( err )
-        err = -EIO; // just something sane
-    return err;
+  err = cyg_flash_program( startpos, (void *)buf, *len, NULL );
+  
+  if ( err )
+    err = -EIO; // just something sane
+  return err;
 } // flashiodev_bwrite()
 
 static Cyg_ErrNo
@@ -174,68 +186,65 @@ flashiodev_get_config( cyg_io_handle_t h
                        void* buf,
                        cyg_uint32* len)
 {
-	struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
-	struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
-
-    switch (key) {
-    case CYG_IO_GET_CONFIG_FLASH_ERASE:
+  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
+  
+  switch (key) {
+  case CYG_IO_GET_CONFIG_FLASH_ERASE:
     {
-        if ( *len != sizeof( cyg_io_flash_getconfig_erase_t ) )
-             return -EINVAL;
-        {
-            cyg_io_flash_getconfig_erase_t *e = (cyg_io_flash_getconfig_erase_t *)buf;
-            char *startpos = dev->start + e->offset;
-
+      if ( *len != sizeof( cyg_io_flash_getconfig_erase_t ) )
+        return -EINVAL;
+      {
+        cyg_io_flash_getconfig_erase_t *e = (cyg_io_flash_getconfig_erase_t *)buf;
+        cyg_flashaddr_t startpos = dev->start + e->offset;
+        
 #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
-            char *endpos = startpos + e->len - 1;
-            char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1);
-            if ( startpos < dev->start )
-                return -EINVAL;
-            if ( endpos > flashend )
-                return -EINVAL;
+        cyg_flashaddr_t endpos = startpos + e->len - 1;
+        if ( startpos < dev->start )
+          return -EINVAL;
+        if ( endpos > dev->end )
+          return -EINVAL;
 #endif
-            e->flasherr = flash_erase( startpos, e->len, e->err_address );
-        }
-        return ENOERR;
+        e->flasherr = cyg_flash_erase( startpos, e->len, e->err_address );
+      }
+      return ENOERR;
     }
-    case CYG_IO_GET_CONFIG_FLASH_DEVSIZE:
+  case CYG_IO_GET_CONFIG_FLASH_DEVSIZE:
     {
-        if ( *len != sizeof( cyg_io_flash_getconfig_devsize_t ) )
-             return -EINVAL;
-        {
-            cyg_io_flash_getconfig_devsize_t *d =
-                (cyg_io_flash_getconfig_devsize_t *)buf;
-
-	    //d->dev_size = flash_info.blocks * flash_info.block_size;
-			d->dev_size = dev->end - dev->start;
-        }
-        return ENOERR;
+      if ( *len != sizeof( cyg_io_flash_getconfig_devsize_t ) )
+        return -EINVAL;
+      {
+        cyg_io_flash_getconfig_devsize_t *d =
+          (cyg_io_flash_getconfig_devsize_t *)buf;
+        
+        d->dev_size = dev->end - dev->start;
+      }
+      return ENOERR;
     }
-
-    case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE:
+    
+  case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE:
     {
-        cyg_io_flash_getconfig_blocksize_t *b =
-            (cyg_io_flash_getconfig_blocksize_t *)buf;
+      cyg_io_flash_getconfig_blocksize_t *b =
+        (cyg_io_flash_getconfig_blocksize_t *)buf;
 #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
-       char *startpos = dev->start + b->offset;
-	    char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1);
-
-        if ( startpos < dev->start )
-            return -EINVAL;
-        if ( startpos > flashend )
-            return -EINVAL;
+      cyg_flashaddr_t startpos = dev->start + b->offset;
+      
+      if ( startpos < dev->start )
+        return -EINVAL;
+      if ( startpos > dev->end )
+        return -EINVAL;
 #endif  
-        if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) )
-             return -EINVAL;
-        
-        // offset unused for now
-		b->block_size = flash_info.block_size;
-        return ENOERR;
+      if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) )
+        return -EINVAL;
+      
+      // offset unused for now
+      b->block_size = dev->block_size;
+      return ENOERR;
     }
-
-    default:
-        return -EINVAL;
-    }
+    
+  default:
+    return -EINVAL;
+  }
 } // flashiodev_get_config()
 
 static Cyg_ErrNo
@@ -244,46 +253,88 @@ flashiodev_set_config( cyg_io_handle_t h
                        const void* buf,
                        cyg_uint32* len)
 {
-#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1
-	struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
-	struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
-#endif
-
-    switch (key) {
-#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1
-    case CYG_IO_SET_CONFIG_FLASH_FIS_NAME:
+  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
+  
+  switch (key) {
+  case CYG_IO_SET_CONFIG_FLASH_FIS_NAME:
     {
-        CYG_ADDRESS     flash_base;
-	unsigned long   size;
+      cyg_flashaddr_t flash_base;
+      unsigned long size;
+      cyg_flash_info_t info;
+      cyg_uint32 i;
+      int stat;
+      
+      if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, 
+                                      (char *)buf, &flash_base))
+        return -ENOENT;
+      if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, 
+                                      (char *)buf, &size))
+        return -ENOENT;
+      
+      dev->start = flash_base;
+      dev->end = flash_base + size;
 
-	if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, 
-                                        (char *)buf, &flash_base))
-	    return -ENOENT;
-	if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, 
-					(char *)buf, &size))
-	    return -ENOENT;
-			
-	dev->start = (char *)flash_base;
-	dev->end = (char *)flash_base + size;
-	return ENOERR;
+      stat = cyg_flash_get_info_addr(dev->start, &info);
+      if (stat != CYG_FLASH_ERR_OK) {
+        return -ENOENT;
+      }
+      dev->block_size = 0;
+      for (i=0; i < info.num_block_infos; i++){
+        dev->block_size = MAX(dev->block_size, info.block_info[i].block_size);
+      }
+      return ENOERR;
     }
-#endif
-    default:
-        return -EINVAL;
-    }
+  default:
+    return -EINVAL;
+  }
 } // flashiodev_set_config()
 
 // get_config/set_config should be added later to provide the other flash
 // operations possible, like erase etc.
 
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1
+static struct flashiodev_priv_t priv1 = {
+  0,       // start
+  0,       // end
+  1,       // use_fis
+  0,       // use_static
+  0.       // use_offset
+  CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1,
+  0        // blocksize
+};
+
+#endif
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_1 
+static struct flashiodev_priv_t priv1 = {
+  CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_1,       // start
+  CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_1 + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_1,
+  0,       // use_fis
+  1,       // use_static
+  0,       // use_offset
+  "",      // fis_name
+  0        // blocksize
+};
+#else
+static struct flashiodev_priv_t priv1 = {
+  CYGNUM_IO_FLASH_BLOCK_OFFSET_1,       // start
+  CYGNUM_IO_FLASH_BLOCK_LENGTH_1,       // end 
+  0,       // use_fis
+  0,       // use_static
+  1,       // use_offset
+  "",      // fis_name
+  0        // blocksize
+};
+#endif
+
 BLOCK_DEVIO_TABLE( cyg_io_flashdev1_ops,
                    &flashiodev_bwrite,
                    &flashiodev_bread,
                    0, // no select
                    &flashiodev_get_config,
                    &flashiodev_set_config
-    ); 
-                   
+                   ); 
+
 
 BLOCK_DEVTAB_ENTRY( cyg_io_flashdev1,
                     CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1,
@@ -291,6 +342,51 @@ BLOCK_DEVTAB_ENTRY( cyg_io_flashdev1,
                     &cyg_io_flashdev1_ops,
                     &flashiodev_init,
                     0, // No lookup required
-                    &flashiodev_priv[0] );
+                    &priv1 );
+
+
+#ifdef CYGSEM_IO_FLASH_BLOCK_DEVICE_2 
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_2
+static struct flashiodev_priv_t priv2 = {
+  0,       // start
+  0,       // end
+  1,       // use_fis
+  0,       // use_static
+  0.       // use_offset
+  CYGDAT_IO_FLASH_BLOCK_FIS_NAME_2,
+  0        // blocksize
+};
+
+#endif
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_2 
+static struct flashiodev_priv_t priv2 = {
+  CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_2,       // start
+  CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_2 + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_2,
+  0,       // use_fis
+  1,       // use_static
+  0,       // use_offset
+  "",      // fis_name
+  0        // blocksize
+};
+#else
+static struct flashiodev_priv_t priv2 = {
+  CYGNUM_IO_FLASH_BLOCK_OFFSET_2,       // start
+  CYGNUM_IO_FLASH_BLOCK_LENGTH_2,       // end 
+  0,       // use_fis
+  0,       // use_static
+  1,       // use_offset
+  "",      // fis_name
+  0        // blocksize
+};
+#endif
+
+BLOCK_DEVTAB_ENTRY( cyg_io_flashdev2,
+                    CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_2,
+                    0,
+                    &cyg_io_flashdev1_ops,
+                    &flashiodev_init,
+                    0, // No lookup required
+                    &priv2 );
+#endif
 
 // EOF flashiodev.c
new file mode 100644
--- /dev/null
+++ b/packages/io/flash/current/src/legacy_api.c
@@ -0,0 +1,102 @@
+//==========================================================================
+//
+//      legacy_api.c
+//
+//      Legacy API implementation on top of the new API
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 Andrew Lunn
+//
+// 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2004-07-02
+// Purpose:      
+// Description:  Implement an interface to the legacy device drivers
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/io_flash.h>
+
+#define  _FLASH_PRIVATE_
+#include <cyg/io/flash.h>
+
+int
+flash_init(_printf *pf)
+{
+  return cyg_flash_init(pf);
+}
+
+int
+flash_verify_addr(void *target)
+{
+  return cyg_flash_verify_addr((cyg_flashaddr_t) target);
+}
+
+int
+flash_get_limits(void *target, void **start, void **end)
+{
+  return cyg_flash_get_limits((cyg_flashaddr_t *)start, 
+                              (cyg_flashaddr_t *)end);
+}
+
+int
+flash_get_block_info(int *block_size, int *blocks)
+{
+  return cyg_flash_get_block_info((size_t *)block_size, blocks);
+}
+
+int
+flash_erase(void *addr, int len, void **err_addr)
+{
+  return cyg_flash_erase((cyg_flashaddr_t)addr, len, 
+                         (cyg_flashaddr_t *)err_addr);
+}
+
+int flash_program(void *flash_base, void *ram_base, int len, 
+                  void **err_address)
+{
+  return cyg_flash_program((cyg_flashaddr_t)flash_base, ram_base, 
+                           len, (cyg_flashaddr_t *)err_address);
+}
+
+int flash_read(void *flash_base, void *ram_base, int len, void **err_address)
+{
+  return cyg_flash_read((cyg_flashaddr_t)flash_base, ram_base, 
+                        len, (cyg_flashaddr_t *)err_address);
+}
new file mode 100644
--- /dev/null
+++ b/packages/io/flash/current/src/legacy_dev.c
@@ -0,0 +1,284 @@
+//==========================================================================
+//
+//      legacy_dev.c
+//
+//      Interface to the legacy device drivers 
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 Andrew Lunn
+//
+// 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2004-07-02
+// Purpose:      
+// Description:  Implement an interface to the legacy device drivers
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/io_flash.h>
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_cache.h>
+#include <string.h>
+
+#define  _FLASH_PRIVATE_
+#include <cyg/io/flash.h>
+
+// When this flag is set, do not actually jump to the relocated code.
+// This can be used for running the function in place (RAM startup only),
+// allowing calls to diag_printf() and similar.
+#undef RAM_FLASH_DEV_DEBUG
+#if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
+# warning "Can only enable the flash debugging when configured for RAM startup"
+#endif
+
+struct flash_info flash_info;
+
+// These are the functions in the HW specific driver we need to call.
+typedef void code_fun(void*);
+
+externC code_fun flash_query;
+externC code_fun flash_erase_block;
+externC code_fun flash_program_buf;
+externC code_fun flash_read_buf;
+externC code_fun flash_lock_block;
+externC code_fun flash_unlock_block;
+
+// Initialize the device
+static int 
+legacy_flash_init (struct cyg_flash_dev *dev)
+{
+  int err;
+  static cyg_block_info_t block_info[1];
+
+  err=flash_hwr_init();
+
+  if (!err) {
+    dev->start = (cyg_flashaddr_t)flash_info.start;
+    dev->end = (cyg_flashaddr_t)flash_info.end;
+    dev->num_block_infos = 1;
+    dev->block_info = block_info;
+    block_info[0].block_size = flash_info.block_size;
+    block_info[0].blocks = flash_info.blocks;
+  }
+  return err;
+}
+
+// Use this function to make function pointers anonymous - forcing the
+// compiler to use jumps instead of branches when calling driver
+// services.
+static void* __anonymizer(void* p)
+{
+  return p;
+}
+
+static size_t 
+legacy_flash_query (struct cyg_flash_dev *dev, 
+                    void * data, 
+                    const size_t len)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+
+static size_t 
+legacy_flash_query (struct cyg_flash_dev *dev, 
+                    void * data, 
+                    const size_t len)
+{
+  typedef void code_fun(void*);
+  code_fun *_flash_query;
+  
+  _flash_query = (code_fun*) __anonymizer(&flash_query);
+  
+  (*_flash_query)(data);
+  
+  return len;
+}
+
+static int 
+legacy_flash_erase_block (struct cyg_flash_dev *dev, 
+                          const cyg_flashaddr_t block_base)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+
+static int 
+legacy_flash_erase_block (struct cyg_flash_dev *dev, 
+                          const cyg_flashaddr_t block_base)
+{
+  typedef int code_fun(cyg_flashaddr_t, unsigned int);
+  code_fun *_flash_erase_block;
+  size_t block_size = dev->block_info[0].block_size;
+  
+  _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block);
+
+  return (*_flash_erase_block)(block_base, block_size);
+}
+
+static int
+legacy_flash_program(struct cyg_flash_dev *dev, 
+                     cyg_flashaddr_t base, 
+                     const void* data, const size_t len)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+
+static int
+legacy_flash_program(struct cyg_flash_dev *dev, 
+                     cyg_flashaddr_t base, 
+                     const void* data, const size_t len)
+{
+  typedef int code_fun(cyg_flashaddr_t, const void *, int, unsigned long, int);
+  code_fun *_flash_program_buf;
+  size_t block_size = dev->block_info[0].block_size;
+  size_t block_mask = ~(block_mask -1);
+
+  _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf);
+
+  return (*_flash_program_buf)(base, data, len, block_mask ,block_size);
+}
+
+static int 
+legacy_flash_read (struct cyg_flash_dev *dev, 
+                   const cyg_flashaddr_t base, 
+                   void* data, const size_t len)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+     
+static int 
+legacy_flash_read (struct cyg_flash_dev *dev, 
+                   const cyg_flashaddr_t base, 
+                   void* data, const size_t len)
+{
+#ifdef CYGSEM_IO_FLASH_READ_INDIRECT
+  typedef int code_fun(void *, void *, int, unsigned long, int);
+  code_fun *_flash_read_buf;
+  size_t block_size = dev->block_info[0].block_size;
+  size_t block_mask = ~(block_mask -1);
+
+  _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf);
+  
+  return = (*_flash_read_buf)(base, data, len, block_mask, buffer_size);
+#else
+  memcpy(data,(void *)base, len);
+  return CYG_FLASH_ERR_OK;
+#endif
+}
+
+
+static int 
+legacy_flash_block_lock (struct cyg_flash_dev *dev, 
+                         const cyg_flashaddr_t block_base)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+
+static int 
+legacy_flash_block_lock (struct cyg_flash_dev *dev, 
+                         const cyg_flashaddr_t block_base)
+{
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+  typedef int code_fun(cyg_flashaddr_t);
+  code_fun *_flash_lock_block;
+  
+  _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block);
+
+  return (*_flash_lock_block)(block_base);
+#else
+  return CYG_FLASH_ERR_INVALID;
+#endif
+}
+
+static int 
+legacy_flash_block_unlock (struct cyg_flash_dev *dev, 
+                           const cyg_flashaddr_t block_base)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+     
+static int 
+legacy_flash_block_unlock (struct cyg_flash_dev *dev, 
+                           const cyg_flashaddr_t block_base)
+{
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+  typedef int code_fun(cyg_flashaddr_t, int, int);
+  code_fun *_flash_unlock_block;
+  size_t block_size = dev->block_info[0].block_size;
+  cyg_uint32 blocks = dev->block_info[0].blocks;
+  
+  _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block);
+  
+  return (*_flash_unlock_block)(block_base, block_size, blocks);
+#else
+  return CYG_FLASH_ERR_INVALID;
+#endif
+}
+
+// Map a hardware status to a package error
+static int 
+legacy_flash_hwr_map_error (struct cyg_flash_dev *dev, int err)
+     __attribute__ ((section (".2ram.flash_program_buf")));
+
+static int 
+legacy_flash_hwr_map_error (struct cyg_flash_dev *dev, int err)
+{
+  return flash_hwr_map_error(err);
+}
+
+void
+flash_dev_query(void* data)
+{
+    typedef void code_fun(void*);
+    code_fun *_flash_query;
+    int d_cache, i_cache;
+
+    _flash_query = (code_fun*) __anonymizer(&flash_query);
+
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    (*_flash_query)(data);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+}
+
+CYG_FLASH_FUNS(cyg_legacy_funs, 
+               legacy_flash_init,
+               legacy_flash_query,
+               legacy_flash_erase_block,
+               legacy_flash_program,
+               legacy_flash_read,
+               legacy_flash_hwr_map_error,
+               legacy_flash_block_lock,
+               legacy_flash_block_unlock
+);
+
+CYG_FLASH_DRIVER(cyg_zzlegacy_flashdev, // zz so that it probably comes last.
+                 &cyg_legacy_funs,
+                 NULL,  // Pointer to config structure
+                 0,     // Start address of flash
+                 0);    // Size of private structure
+