This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[flashv2 merge] io/flash


Attached.
-- 
eCosCentric Limited      http://www.eCosCentric.com/     The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK.       Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------       Opinions==mine
Index: packages/io/flash/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/ChangeLog,v
retrieving revision 1.43
diff -u -5 -p -r1.43 ChangeLog
--- packages/io/flash/current/ChangeLog	25 Feb 2006 14:07:43 -0000	1.43
+++ packages/io/flash/current/ChangeLog	18 Nov 2008 00:54:12 -0000
@@ -1,20 +1,314 @@
-2006-02-21  Oliver Munz  <munz@speag.ch>
-	    Andrew Lunn  <andrew.lunn@ascom.ch>
+2008-08-29  Nick Garnett  <nickg@ecoscentric.com>
 
-	* src/flash.c (flash_init): Allow repeat calls change the function
-	used for printing. There are times you don't any output, eg you
-	are downloading am image over the serial port.
+	* src/flashiodev.c (flashiodev_init): Assign
+	CYG_DEVTAB_STATUS_BLOCK to status field of device table
+	entries. This causes devfs to call the right read/write
+	operations.
+
+2008-06-10  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* tests/flashdev.c (FLASH_TEST_LENGTH): Reduce to a
+	multiple of 0x20000 as some flash parts (especially if
+	they are in fact multiple chips in parallel) have that
+	block size.
+	Try opening jffs2test FIS partition if flashtest doesn't exist.
+
+2007-05-14  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/flashiodev.c (flashiodev_get_config): Support new
+	CYG_IO_GET_CONFIG_FLASH_DEVADDR key to get flash device
+	base address.
+	* include/flash.h: Associated structure for key.
+	* doc/flash.sgml: Document CYG_IO_GET_CONFIG_FLASH_DEVADDR.
+
+2006-12-18  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* tests/flash1.c: Replace FLASH_ERR_OK with CYG_FLASH_ERR_OK.
+	* tests/flashdev.c: Ditto. Also flash_errmsg ->
+	cyg_flash_errmsg. And some warning cleanups.
+
+	* src/flashiodev.c (flashiodev_lookup): Correct misplaced else
+	with respect to #ifdefs. Fix for bug 1000355.
+
+2006-12-18  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/flash_legacy.h (FLASH_Enable, FLASH_Disable): Add casts to
+	these macros since the calls in the source don't present the right
+	types. This is mainly an exercise in suppressing compiler
+	warnings.
+
+2006-12-07  Nick Garnett  <nickg@ecoscentric.com>
+
+	* tests/flashdev.c (cyg_start): Fix bug, b.offset should be
+	initialized to 0. Until now it was some random value on the stack,
+	why this has never bitten us before is a mystery.
+
+2006-10-31  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/legacy_dev.c (legacy_flash_program): Define block_size.
+
+2006-10-03  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* doc/flash.sgml: Bring into line with actual implementation.
+	Also some trivial typos.
+
+2006-08-01  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/flash.c (cyg_flash_devfn_lock_nop): Don't return error
+	if this is used with one of multiple flash devices in a
+	system where a different one does support locking.
+	(cyg_flash_devfn_unlock_nop): Ditto.
+
+2006-06-06  John Dallaway  <jld@ecoscentric.com>
+
+	* cdl/io_flash.cdl: Fix reference to package documentation.
+
+2006-05-23  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/flash.c (cyg_flash_erase): Report errors and error
+	addresses correctly.
+	(cyg_flash_program): Ditto.
+
+2005-12-21  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* doc/flash.sgml: Document flash block device lock/unlock config keys.
+
+2005-10-26  Nick Garnett  <nickg@ecoscentric.com>
+
+	* include/flash.h (cyg_io_flash_getconfig_lock_t) 
+	(cyg_io_flash_getconfig_unlock_t): Added these aliases for
+	cyg_io_flash_getconfig_erase_t. 
+
+	* cdl/io_flash.cdl: Added configury to control compilation of
+	flash1 test. Added flashdev test.
+
+	* src/legacy_api.c (flash_lock, flash_unlock): Added these functions.
+
+	* src/flashiodev.c (flashiodev_get_config): Added support for lock
+	and unlock operations.
+
+	* tests/flashdev.c: Added this test to exercise flash /dev/flash
+	device. Functionally it is similar to the flash1 test.
+
+	* tests/flash1.c : Changed test for legacy API.
+	(cyg_start): Added tests for lock and unlock functions.
+
+2005-09-28  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/flash.c (flash_sort_and_check): Allow for Flash
+	device initialisation to fail, and thus not put this device
+	on the Flash device list.
+
+2005-09-26  Bart Veer  <bartv@ecoscentric.com>
+
+	* src/flash.c: put init flag into .bss rather than .data, avoids
+	some problems when performing soft resets.
+
+2005-08-16  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/flash.c (cyg_flash_read): Comment out chatter. It's not
+	very useful for this function.
 
 2005-08-02  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* tests/flash1.c (cyg_start): Compiler warning fixes.
 
+2005-05-27  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* tests/flash1.c (cyg_start): Call CYG_TEST_INIT().
+
 2005-03-27  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* tests/flash1.c: Fixed compiler warning with diag_printf.
 
+2005-02-28  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* include/flash.h: Getconfig/setconfig definitions are relevant for
+	both new and legacy block device support.
+
+2005-01-28  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/legacy_dev.c (legacy_flash_init): Assign flash_info.pf from
+	flash device field. Otherwise drivers try to call an invalid
+	address.
+	(legacy_flash_program): The last argument to flash_program_buf()
+	is not the block size but the programming buffer size.
+
+2005-01-21  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* doc/flash.sgml: Document Flash block devices.
+
+2005-01-19  Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* src/flashiodev.c: Redesign to use more flexible flash names.
+	* src/flashiodevlegacy.c: Previous version of flashiodev.c renamed
+	to this.
+	* cdl/io_flash.cdl: Support new flashiodev design.
+	* include/flash.h: don't double indirect err_address address
+	pointer in cyg_io_flash_getconfig_erase_t.
+	* src/flash_legacy.h: Undef HAL_FLASH_CACHES_* macros if the HAL
+	supplied them and they're not needed.
+
+	* src/legacy_api.c (flash_errmsg): Was missing. Add.
+
+	* tests/flash1.c (cyg_start): Silence warning.
+
+2004-12-02  Bart Veer  <bartv@ecoscentric.com>
+
+	* include/flash_dev.h: now provides everything needed by flash
+	device drivers.
+
+	* include/flash_priv.h: removed, subsumed by flash_dev.h
+	
+	* include/flash.h, src/flash.c, src/flashiodev.c,
+	  src/legacy_api.c, src/legacy_dev.c:
+	Replace implicit #include's of <cyg/io/flash_priv.h> with explicit
+	#include's of <cyg/io/flash_dev.h>
+
+2004-11-29  Bart Veer  <bartv@ecoscentric.com>
+	
+	* include/flash_priv.h, src/flash.c, src/legacy_dev.c: remove
+	hwr_map_error() from V2 drivers
+
+	* include/flash_priv.h, src/flash.c, src/legacy_dev.c: provide
+	dummy init/query/lock/unlock functions for use by device drivers
+	which do not support/need this functionality. Export the
+	anonymizer function.
+
+2004-11-28  John Dallaway  <jld@ecoscentric.com>
+
+	* doc/flash.sgml: Fix minor SGML tag problems.
+
+2004-11-28  Bart Veer  <bartv@ecoscentric.com>
+
+	* src/flash.c (flash_sort_and_check): previous patch would have
+	resulted in init failure if only one device initialized.
+	(cyg_flash_get_info): handle per-device init flag
+
+2004-11-25  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flash.c (flash_sort_and_check): Don't add devices which
+	failed to initialise onto the list. Don't bother sorting the
+	list if its empty or only has one entry.
+	* src/flash.c (find_dev): All devices on the list are initialised so
+	don't both checking the init flag.
+
+2004-11-24  Bart Veer  <bartv@ecoscentric.com>
+
+	* cdl/io_flash.cdl, src/flash.c, src/flash_legacy.h,
+	src/legacy_dev.c: add support for V2 drivers which can take care
+	of the cache and interrupts themselves.
+
+	* tests/flash1.c (cyg_start): mark N/A for now if a V2 driver is
+	being used.
+	* Merge from flash V2 branch
+	
+  2004-11-22  Bart Veer  <bartv@ecoscentric.com>
+
+	* src/legacy_dev.c: remove .2ram attributes. These functions do
+	not manipulate the hardware, there is no need for them to live in
+	ram rather than flash
+	* include/flash_priv.h, src/legacy_dev.c: clean up the interface
+	between the generic flash code and the device drivers
+	* include/flash_priv, src/flash_legacy.h, src/flash.c,
+	src/legacy_dev.c: move cache stuff andother legacy macros
+	to an internal header.
+	* include/flash.h, include/flash_priv.h, doc/flash.sgml,
+	src/flash.c, src/legacy_dev.c: put const in the right places,
+	and rename cyg_block_info to cyg_flash_block_info
+
+  2004-11-21  Bart Veer  <bartv@ecoscentric.com>
+
+	* src/flash.c, include/flash_priv.h, cdl/io_flash.h: optimize
+	for the case of a single flash device.
+	* include/flash.h, src/flash.c, doc/flash.sgml: remove
+	cyg_flash_code_overlaps()
+	* include/flash_priv.h, include/flash.h:
+	CYGSEM_IO_FLASH_LEGACY_DEVICE_API has been removed, test
+	CYGHWR_IO_FLASH_DEVICE_LEGACY instead 
+	* cdl/io_flash.cdl: lots of clean-ups
+	* src/legacy_dev.c (legacy_flash_read): only needed if the
+	underlying legacy driver required indirect reads.
+	* src/flash.c: encapsulate various optional bits of code in
+	macros, to cut down on the #ifdef's in the main code
+
+  2004-11-20  Bart Veer  <bartv@ecoscentric.com>
+
+	* cdl/io_flash.cdl, src/flash.c(cyg_flash_read): add an interface
+	for hardware which requires indirect reads, and suppress
+	unnecessary code if direct reads are always available.
+	* src/flash.c: rearrange loops to avoid address comparisons, which
+	tend to go wrong if the flash is at the end of the address space
+
+  2004-10-06  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/legacy_dev.c (legacy_flash_init): The end is the size plus
+	the start.
+
+  2004-09-30  Savin Zlobec <savin@elatec.si>
+
+	* src/flash.c: Offset into the block is not calculated correctly
+	when the flash start is not aligned on a flash block.
+	* src/legacy_dev.c (legacy_flash_read): Fixed typo.
+
+  2004-09-14  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flash.c (cyg_flash_init): Add assert checking that the
+	end address matches the block information.
+	* src/legacy_dev.c (legacy_flash_init): Ensure that the end
+	address is the last valid address, not the first invalid address.
+
+  2004-09-09  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flash.c: Support flash blocks of arbitary size. The
+	DataFlash devices for example have block of 528 bytes.
+
+  2004-08-21  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+        * removed the functions cyg_flash_get_limits and
+	cyg_flash_get_block_info. Reimplemented the legacy functions
+	that depended on them and flashiodev.c
+	
+  2004-08-19  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flashiodev.c Ordering problem again. If an invalid name is
+	configured the lookup would fail and it then was impossible to do
+	a cyg_io_config_set. Lookup cannot fail because the name does not
+	exist in FIS.
+
+  2004-08-13  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+        * src/flash.c: Make the flock lock/unlock code compile without
+	warnings.
+	* src/flashiodev.c (flashiodev_lookup): Only initialize the device
+	if we have not already been initialized via cyg_set_config().
+	This stopped redboots mount -f working.
+
+  2004-08-09  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flashiodev.c (flashiodev_lookup): Moved most of the
+	flashiodev_init into this new function. This fixed the ordering
+	issue with redboot startup. When doing a FIS name lookup in
+	flashiodev_init, redboot was not yet nitialised so lookup
+	failed. Moving this into flashiodev_lookup solves this problem.
+	Its now possible for redboot to mount the jffs2 filesystem with 
+	-d /dev/flash1.
+
+  2004-08-06  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flashiodev.c: Fix typo in macro and configuration options
+	
+  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-09-05  Mark Salter  <msalter@redhat.com>
 
 	* doc/flash.sgml: Fix unbalanced <PARA>s.
 
 2004-08-24  Gary Thomas  <gary@mlbassoc.com>
@@ -47,11 +341,11 @@
 2003-11-24  Jani Monoses  <jani@iv.ro>
 
 	* cdl/io_flash.cdl:
 	* include/flash.h: Remove CYGNUM_FLASH_WORKSPACE_SIZE cdl option. 
  
-2003-11-24  Roland Caßebohm <roland.cassebohm@visionsystems.de>
+2003-11-24  Roland CaÃ?ebohm <roland.cassebohm@visionsystems.de>
 
 	* src/flashiodev.c (flashiodev_bwrite): Use flash_read rather than
 	directly doing a memcpy. 
 
 2003-11-20  Jani Monoses  <jani@iv.ro>
@@ -329,10 +623,11 @@
 //===========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2005, 2006, 2008 eCosCentric Limited
 //
 // 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.
 //
@@ -352,11 +647,8 @@
 // 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####
 //===========================================================================
Index: packages/io/flash/current/cdl/io_flash.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/cdl/io_flash.cdl,v
retrieving revision 1.18
diff -u -5 -p -r1.18 io_flash.cdl
--- packages/io/flash/current/cdl/io_flash.cdl	24 Aug 2004 13:17:18 -0000	1.18
+++ packages/io/flash/current/cdl/io_flash.cdl	18 Nov 2008 00:54:12 -0000
@@ -6,12 +6,14 @@
 #
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
 ## -------------------------------------------
 ## This file is part of eCos, the Embedded Configurable Operating System.
-## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+## Copyright (C) 2004, 2006 eCosCentric Ltd
+## Copyright (C) 2004 Andrew Lunn
 ## Copyright (C) 2003, 2004 Gary Thomas
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 ##
 ## eCos is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free
 ## Software Foundation; either version 2 or (at your option) any later version.
 ##
@@ -41,87 +43,114 @@
 # ====================================================================
 ######DESCRIPTIONBEGIN####
 #
 # Author(s):      gthomas
 # Original data:  gthomas
-# Contributors:   woehler
+# Contributors:   woehler, bartv
 # Date:           2000-07-06
 #
 #####DESCRIPTIONEND####
 #
 # ====================================================================
 
 cdl_package CYGPKG_IO_FLASH {
-    display       "FLASH device drivers"
-    include_dir   cyg/io
-    doc           ref/flash.html
-    description   "
-        This option enables drivers for basic I/O services on
-        flash devices."
-    requires CYGPKG_ISOINFRA
-    requires CYGINT_ISO_STRING_STRFUNCS
+    display         "FLASH device drivers"
+    include_dir     cyg/io
+    doc             ref/io-flash.html
+    description     "
+        This package provides support for the flash devices on the
+        current platform."
+    requires    CYGPKG_ISOINFRA
+    requires    CYGINT_ISO_STRING_STRFUNCS
 
-    compile       flash.c
+    compile     flash.c
  
-    define_proc {
-        puts $::cdl_header "#include <pkgconf/system.h>"
-        puts $::cdl_header "#ifdef CYGDAT_IO_FLASH_DEVICE_HEADER"
-        puts $::cdl_header "# include CYGDAT_IO_FLASH_DEVICE_HEADER"
-        puts $::cdl_header "#endif "
-    }
-
     cdl_interface CYGHWR_IO_FLASH_DEVICE {
-        display       "Hardware FLASH device drivers"
-        description   "
-            This option enables the hardware device drivers
-            for the current platform."
-    }
-
-    cdl_interface CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM {
-        display       "Hardware FLASH device drivers are not in RAM"
-        flavor        booldata
-        description   "
-            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
+        display     "Hardware FLASH device drivers"
+	requires    { CYGHWR_IO_FLASH_DEVICE >= 1 }
+        description "
+            This calculated option gives the number of flash devices
+            on the current platform. The generic flash support requires
+            at least one device."
     }
 
     cdl_interface CYGHWR_IO_FLASH_BLOCK_LOCKING {
-        display       "Hardware can support block locking"
-        flavor        booldata
-        description   "
+        display     "Hardware can support block locking"
+        flavor      booldata
+        description "
             This option will be enabled by devices which can support
-            locking (write-protection) of individual blocks."
+            locking (write-protection) of individual flash blocks. If
+            none of the devices support locking then the relevant code
+            in the generic flash package can be eliminated."
+    }
+
+    cdl_interface CYGHWR_IO_FLASH_INDIRECT_READS {
+	display	    "Hardware requires indirect reads"
+	flavor	    booldata
+	description "
+            Some flash devices can be read directly like any other
+            memory. Others can only be accessed indirectly, which
+            involves extra code. If none of the flash devices on the
+            target hardware use indirect reads then the extra code
+            can be eliminated."
+    }
+    
+    cdl_interface CYGHWR_IO_FLASH_DEVICE_NEEDS_CACHE_HANDLED {
+	display	    "Device driver needs cache handled centrally"
+	flavor	    booldata
+	description "
+            Managing flash often requires interacting with the cache.
+            Some device drivers do not require the generic flash code to
+            manipulate the cache, either because they do it themselves or
+            because the hardware does the right thing. Other drivers
+            require the generic code to disable/enable the cache before
+            calling into the driver."
+    }
+    
+    cdl_interface CYGHWR_IO_FLASH_DEVICE_LEGACY {
+        display     "Hardware driver uses the legacy interface"
+        flavor      booldata
+        compile     -library=libextras.a legacy_dev.c
+        description "
+            The generic flash code can work with either a legacy device
+            driver or with V2 drivers. If a legacy driver is used on the
+            current platform then this option will be implemented."
+	requires    { CYGHWR_IO_FLASH_DEVICE_LEGACY <= 1 }
+
+        # For now assume all legacy devices need the cache handled by
+        # the central code
+        implements CYGHWR_IO_FLASH_DEVICE_NEEDS_CACHE_HANDLED
     }
 
     cdl_option CYGSEM_IO_FLASH_READ_INDIRECT {
-        display       "Hardware cannot support direct access to FLASH memory"
-        flavor        bool
-        default_value 0
-        requires      { !CYGSEM_IO_FLASH_VERIFY_PROGRAM }
-        description   "
+	display         "Legacy device driver uses indirect reads."
+	active_if       CYGHWR_IO_FLASH_DEVICE_LEGACY
+        flavor          bool
+        default_value   0
+        requires        { !CYGSEM_IO_FLASH_VERIFY_PROGRAM }
+        description     "
             This option will be asserted by devices which cannot support
             direct access to the FLASH memory contents (e.g. EEPROM or NAND
             devices).  In these cases, the driver must provide an appropriate
             hardware access function."
     }
 
     cdl_option CYGSEM_IO_FLASH_CHATTER {
-        display          "Display status messages during flash operations"
-        flavor           bool
-        default_value    1
-        description      "
-           Selecting this option will cause the drivers to print status
+        display         "Display status messages during flash operations"
+        flavor          bool
+        default_value   1
+        description     "
+           Selecting this option will cause the flash code to print status
            messages as various flash operations are undertaken."
     }
 
     cdl_option CYGSEM_IO_FLASH_VERIFY_PROGRAM {
-        display          "Verify data programmed to flash"
-        flavor           bool
-        default_value    1
-        description      "
+        display         "Verify data programmed to flash"
+        flavor          bool
+        default_value   1
+	active_if	{ CYGHWR_IO_FLASH_INDIRECT_READS < CYGHWR_IO_FLASH_DEVICE }
+        description     "
            Selecting this option will cause verification of data
            programmed to flash."
     }
 
     cdl_option CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT {
@@ -133,71 +162,204 @@ cdl_package CYGPKG_IO_FLASH {
            dipswitch to be read by software to determine whether the flash is
            write-protected or not."
     }
 
     cdl_component CYGPKG_IO_FLASH_BLOCK_DEVICE {
-        display         "Instantiate in I/O block device API"
+        display         "Provide /dev block devices"
         flavor          bool
         active_if       CYGPKG_IO
         default_value   0
         compile         -library=libextras.a flashiodev.c
+        requires        { CYGINT_IO_FLASH_BLOCK_DEVICE_METHODS > 0}
         description     "
-                Provides a block device accessible using the standard I/O
-                API ( cyg_io_read() etc. )"
+            Provide one or more block devices below /dev which can be
+            accessed using standard I/O functions such as eCos cyg_io_read()
+            and POSIX open()."
+
+        cdl_interface CYGINT_IO_FLASH_BLOCK_DEVICE_METHODS {
+            display         "Number of methods to reference Flash"
+            flavor          bool
+            no_define
+            description     "This interface counts the number of ways Flash can
+                             be referenced in order to be opened. This is so that
+                             the configuration can ensure that at least one method
+                             is available."
+        }
 
-        cdl_component CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1 {
-			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_option CYGNUM_IO_FLASH_BLOCK_DEVICES {
+            display         "Number of /dev/flash/ device slots"
+            flavor          data
+            default_value   2
+            description     "The number of simultaneously open flash devices
+                             permitted. This is statically configured, rather than
+                             dynamically allocated at run-time as it is likely the
+                             number required will be small."
+        }
 
-			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_option CYGFUN_IO_FLASH_BLOCK_FROM_FIS {
+            display         "Access using named FIS areas"
+            requires        CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+            default_value   CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+            implements      CYGINT_IO_FLASH_BLOCK_DEVICE_METHODS
+            description     "This method of access to Flash regions uses the names
+                             of FIS regions to identify the Flash device, or portion
+                             of the device. For example /dev/flash/fis/jffs2."
+        }
+        cdl_option CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET {
+            display         "Access using device numbers,offsets"
+            default_value   1
+            implements      CYGINT_IO_FLASH_BLOCK_DEVICE_METHODS
+            description     "This method of access to Flash regions uses the Flash
+                             device number, along with an offset (which may be
+                             0 to indicate the start of the device) and an optional length
+                             which will otherwise be assumed to be the whole device.
+                             For example /dev/flash/0/0x1000 or
+                             /dev/flash/1/0,65536."
         }
     }
 
+    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_component CYGPKG_IO_FLASH_BLOCK_DEVICE_LEGACY {
+        display         "Provide /dev block devices (legacy format)"
+        flavor          bool
+        active_if       CYGPKG_IO
+        default_value   0
+        compile         -library=libextras.a flashiodevlegacy.c
+        description     "
+            Provide one or more block devices below /dev which can be
+            accessed using standard I/O functions such as eCos cyg_io_read()
+            and POSIX open(). This format of configuration is deprecated,
+            but is included for compatibility with older configurations."
+
+	for { set ::dev 1 } { $::dev <= 2 } { incr ::dev } {
+	    
+	    cdl_component CYGPKG_IO_FLASH_BLOCK_DEVICE_$::dev {
+		display       "Provide block device $::dev"
+		if { 1 == $::dev } {
+		    default_value 1
+		} else {
+		    default_value 0
+		}
+		description "Provide block device $::dev for use with standard I/O"
+
+		cdl_option CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_$::dev {
+		    display       "Name of flash block device $::dev"
+		    flavor        data
+		    default_value "\"\\\"/dev/flash$::dev\\\"\""
+		    description "
+                        This option determines the name by which the block
+                        device can be accessed."
+		}
+		
+		cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_$::dev {
+		    requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_$::dev
+		    no_define
+		}
+
+		cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_$::dev {
+		    display         "Static configuration via offset"
+		    default_value   1
+		    implements      CYGINT_IO_FLASH_BLOCK_CFG_$::dev
+		    description     "
+                        This configures the flash block device $::dev
+                        with static offset from the base of the first
+                        flash device and length"
+		    
+		    cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_$::dev {
+			display         "Start offset from flash base"
+			flavor          data
+			default_value   0xFFFFFFFF
+			requires        0xFFFFFFFF != CYGNUM_IO_FLASH_BLOCK_OFFSET_$::dev
+			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_$::dev {
+			display         "Length"
+			flavor          data
+			default_value   0
+			requires        0 != CYGNUM_IO_FLASH_BLOCK_OFFSET_$::dev
+			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_$::dev {
+		    display         "Static configuration via absolute address"
+		    default_value   0
+		    implements      CYGINT_IO_FLASH_BLOCK_CFG_$::dev
+		    description     "
+                        This configures the flash block device $::dev
+                        with absolute base address and a length"
+		    
+		    cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_$::dev {
+			display         "Start offset from flash base"
+			flavor          data
+			default_value   0xFFFFFFFF
+			requires        0xFFFFFFFF != CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_$::dev
+			description     "
+                            This gives the absolute address in flash which this
+                            block device corresponds to."
+		    }
+		    cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_$::dev {
+			display         "Length"
+			flavor          data
+			default_value   0
+			requires	0 != CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_$::dev
+			description     "
+                            This gives the length of the region of flash given over
+                            to this block device."
+		    }
+		}
+		
+		cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_$::dev {
+		    display         "Configuration from FIS"
+		    default_value   0
+		    implements      CYGINT_IO_FLASH_BLOCK_CFG_$::dev
+		    description     "
+                          This configures the flash block device $::dev
+                          from Redboot FIS"
+		    
+		    cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_$::dev {
+			display     "Name of FIS entry"
+			flavor      data
+			requires    "\"\"" != CYGDAT_IO_FLASH_BLOCK_FIS_NAME_$::dev
+			if { 1 == $::dev } {
+			    default_value { "\"jffs2\"" }
+			} elseif { 2 == $::dev } {
+			    default_value { "\"jffs2-2\"" }
+			} else {
+			    default_value { "\"\"" }
+			}
+		    }
+		}
+            }
+	}
+    }
+
+    # FIXME: remove in next release
+    cdl_interface CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM {
+        display       "Hardware FLASH device drivers are not in RAM"
+        flavor        booldata
+        description   "
+            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
+    }
+
     cdl_component CYGPKG_IO_FLASH_OPTIONS {
         display "Flash device driver build options"
         flavor  none
         description   "
 	    Package specific build options including control over
@@ -229,30 +391,60 @@ cdl_package CYGPKG_IO_FLASH {
 
         cdl_component CYGPKG_IO_FLASH_TESTS {
             display "Flash device driver tests"
             flavor  data
             no_define
-            calculated { "tests/flash1" }
+#            requires   { CYGINT_IO_FLASH_TESTS_ADDR_METHOD == 1 }
+            calculated { (CYGSEM_IO_FLASH_LEGACY_API ? "tests/flash1" : "") .
+                         (CYGPKG_IO_FLASH_BLOCK_DEVICE ? " tests/flashdev" : "") }
             description   "
                 This option specifies the set of tests for the flash device drivers."
 
-            cdl_option CYGNUM_IO_FLASH_TEST_OFFSET {
-                display         "Start offset from flash base"
-                flavor          data
-                default_value   0x100000
-                description     "
-                    This gives the offset from the base of flash where tests
-                    can be run.  It is important to set this correctly, as an
-                    incorrect value could allow the tests to write over critical
-                    portions of the FLASH device and possibly render the target
-                    board totally non-functional."
-            }
-            cdl_option CYGNUM_IO_FLASH_TEST_LENGTH {
-                display         "Length"
-                flavor          data
-                default_value   0x100000
-                description     "
-                    This gives the length of the region of flash used for testing."
-            }
+#            cdl_interface CYGINT_IO_FLASH_TESTS_ADDR_METHOD {
+#                display       "Set single Flash access method"
+#            }
+#        
+#
+#            cdl_option CYGTST_IO_FLASH_TESTS_ADDR_FIS {
+#                display       "Use \"flashtest\" FIS entry"
+#                default_value CYGFUN_IO_FLASH_BLOCK_FROM_FIS
+#                implements    CYGINT_IO_FLASH_TESTS_ADDR_METHOD
+#                requires      CYGFUN_IO_FLASH_BLOCK_FROM_FIS
+#                requires      !CYGTST_IO_FLASH_TESTS_ADDR_HARDCODE
+#                description   "
+#                        This option means that tests will use the Flash region
+#                        identified by the \"flashtest\" FIS entry if it is found."
+#            }
+#
+#            cdl_component CYGTST_IO_FLASH_TESTS_ADDR_HARDCODE {
+#                display       "Use hardcoded offset from Flash base"
+#                default_value !CYGTST_IO_FLASH_TESTS_ADDR_FIS
+#                implements    CYGINT_IO_FLASH_TESTS_ADDR_METHOD
+#                requires      !CYGTST_IO_FLASH_TESTS_ADDR_FIS
+#                description   "
+#                        This option means that tests will use the flash region
+#                        identified by the \"flashtest\" FIS entry if it is found."
+#
+                cdl_option CYGNUM_IO_FLASH_TEST_OFFSET {
+                    display         "Start offset from flash base"
+                    flavor          data
+                    default_value   0x100000
+                    description     "
+                        This gives the offset from the base of flash where tests
+                        can be run.  It is important to set this correctly, as an
+                        incorrect value could allow the tests to write over critical
+                        portions of the FLASH device and possibly render the target
+                        board totally non-functional."
+                }
+                cdl_option CYGNUM_IO_FLASH_TEST_LENGTH {
+                    display         "Length"
+                    flavor          data
+                    default_value   0x100000
+                    description     "
+                        This gives the length of the region of flash used for testing."
+                }
+#            }
         }
     }
 }
+
+# EOF io_flash.cdl
Index: packages/io/flash/current/doc/flash.sgml
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/doc/flash.sgml,v
retrieving revision 1.2
diff -u -5 -p -r1.2 flash.sgml
--- packages/io/flash/current/doc/flash.sgml	5 Sep 2004 20:13:45 -0000	1.2
+++ packages/io/flash/current/doc/flash.sgml	18 Nov 2008 00:54:13 -0000
@@ -1,5 +1,7 @@
+<!-- DOCTYPE part  PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+
 <!-- {{{ Banner                         -->
 
 <!-- =============================================================== -->
 <!--                                                                 -->
 <!--     flash.sgml                                                  -->
@@ -9,10 +11,11 @@
 <!-- =============================================================== -->
 <!-- ####COPYRIGHTBEGIN####                                          -->
 <!--                                                                 -->
 <!-- =============================================================== -->
 <!-- Copyright (C) 2004 Andrew Lunn                                  -->
+<!-- Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited        -->
 <!-- This material may be distributed only subject to the terms      -->
 <!-- and conditions set forth in the Open Publication License, v1.0  -->
 <!-- or later (the latest version is presently available at          -->
 <!-- http://www.opencontent.org/openpub/)                            -->
 <!-- Distribution of the work or derivative of the work in any       -->
@@ -33,13 +36,10 @@
 <TITLE>FLASH Library</TITLE>
 <CHAPTER id="ecos-flash-library">
 <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>
 <listitem><PARA>Identifying installed device of a FLASH family.
           </PARA>
@@ -48,10 +48,330 @@
 <listitem><PARA>Validating an address is within the FLASH.</PARA></listitem>
 <listitem><PARA>Determining the number and size of FLASH blocks.
           </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 id="io-flash-danger">
+<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>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);
+__extern size_t cyg_flash_block_size(const cyg_flashaddr_t flash_base);
+
+typedef struct cyg_flash_block_info
+    size_t                    block_size;
+    cyg_uint32                blocks;
+} cyg_flash_block_info_t;
+
+typedef struct {
+    cyg_flashaddr_t              start;          // First address
+    cyg_flashaddr_t              end;            // Last address
+    cyg_uint32                   num_block_infos // Number of entries
+    const cyg_flash_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> is 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.
+</PARA>
+</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(cyg_flashaddr_t flash_base, void *ram_base, size_t len, cyg_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(cyg_flashaddr_t flash_base, size_t len, cyg_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> may be 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(cyg_flashaddr_t flash_base, void *ram_base, size_t len, cyg_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 cyg_flashaddr_t flash_base, size_t len, cyg_flashaddr_t *err_address);
+__externC int cyg_flash_unlock(const cyg_flashaddr_t flash_base, size_t len, cyg_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 cyg_flashaddr_t from, size_t len);
+__externC int cyg_flash_mutex_unlock(const cyg_flashaddr_t from, size_t len);
+</PROGRAMLISTING>
+
+</SECT2
+
+<SECT2>
+
+<TITLE>Return values and errors</TITLE>
+
+<PARA>All the functions above 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>
+
+<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 {
+  const struct cyg_flash_dev_funs *funs;            // Function pointers
+  cyg_uint32                      flags;            // Device characteristics
+  cyg_flashaddr_t                 start;            // First address
+  cyg_flashaddr_t                 end;              // Last address
+  cyg_uint32                      num_block_infos;  // Number of entries
+  const cyg_flash_block_info_t    *block_info;      // Info about one block size
+
+  const void                      *priv;            // Devices private data
+
+  // 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
+#if (CYGHWR_IO_FLASH_DEVICE > 1)    
+  struct cyg_flash_dev            *next;            // Pointer to next device
+#endif    
+};
+
+struct cyg_flash_dev_funs {
+  int     (*flash_init) (struct cyg_flash_dev *dev);
+  size_t  (*flash_query) (struct cyg_flash_dev *dev, void * data, size_t len);
+  int     (*flash_erase_block) (struct cyg_flash_dev *dev, cyg_flashaddr_t block_base);
+  int     (*flash_program) (struct cyg_flash_dev *dev, cyg_flashaddr_t base, const void* data, size_t len);
+  int     (*flash_read) (struct cyg_flash_dev *dev, const cyg_flashaddr_t base, void* data, size_t len);
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING    
+  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);
+#endif    
+};
+</PROGRAMLISTING>
+
+<PARA>The FLASH IO layer will only pass requests for operations on a single block.</PARA>
+</SECT2>
+</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>
 
 <orderedlist>
 <listitem><PARA>Only one family of FLASH device may be supported at once.
@@ -70,24 +390,32 @@ The library has a number of limitations:
                  future but backward compatibility is likely to be kept.
           </PARA>
 </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>
 
 <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 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
 which is to be used for diagnostic output. Typically the function
 <function>diag_printf()</function> will be passed. Normally this
@@ -179,11 +507,11 @@ erase in the FLASH and <PARAMETER>err_ad
 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>
+</PARAMETER> may be anywhere in the last block to be erased.  </PARA>
 
 </SECT2>
 <SECT2>
 
 <TITLE>Programming the FLASH</TITLE>
@@ -264,47 +592,461 @@ explains some of the problems with the l
 <PARA>The library is not thread safe. Multiple simultaneous calls to
 its library functions will likely fail and may cause a crash. It is
 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.
-</PARA>
+</SECT2>
+</SECT1>
 
-<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 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>
 
-<TITLE>Danger, Will Robinson! Danger!</TITLE>
+<PARA>The FLASH IO library will call the following function to
+initialize the device driver:</PARA>
 
-<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?
+<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>
+
+<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>
+
+<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>
+
+<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>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.</PARA>
+
+</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>
+
+<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>
-</SECT1> 
+
+<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> 
+
+<CHAPTER id="ecos-flash-iodevice">
+<TITLE>FLASH I/O devices</TITLE>
+
+<PARA>
+It can be useful to be able to access FLASH devices using the generic
+I/O infrastructure found in <varname>CYGPKG_IO</varname>, and the generic
+FLASH layer provides an optional ability to do so. This allows
+the use of functions like <function>cyg_io_lookup()</function>,
+<function>cyg_io_read()</function>,
+<function>cyg_io_write()</function> etc.
+</PARA>
+<PARA> Additionally it means that, courtesy of the
+&ldquo;devfs&rdquo; pseudo-filesystem in the file I/O layer
+(<varname>CYGPKG_IO_FILEIO</varname>), functions like
+<function>open()</function>, <function>read()</function>,
+<function>write()</function> etc. can even be used directly
+on the FLASH devices.
+</PARA>
+
+<SECT1 id="ecos-flash-iodevice-overview-config">
+<TITLE>Overview and CDL Configuration</TITLE>
+
+<PARA>
+This package implements support for FLASH as an I/O device by exporting
+it as if it is a block device. To enable this support, the CDL option
+titled &ldquo;Provide /dev block devices&rdquo;, also known as
+<varname>CYGPKG_IO_FLASH_BLOCK_DEVICE</varname>, must be enabled.
+(There is also a legacy format alternative which is now deprecated).
+</PARA>
+<PARA>
+There are two methods of addressing FLASH as a block device:</PARA>
+
+<orderedlist>
+<listitem><para>Using the FLASH Information System (FIS) - this is a
+method of defining and naming FLASH partitions, usually in RedBoot.
+This option is only valid if RedBoot is resident and was used to
+boot the application. To reference FLASH partitions in this way,
+you would use a device name of the form
+<filename>/dev/flash/fis/<replaceable>partition-name</replaceable></filename>,
+for example <filename>/dev/flash/fis/jffs2</filename> to reference a
+FIS partition named JFFS2.</para>
+
+<para>The CDL option <varname>CYGFUN_IO_FLASH_BLOCK_FROM_FIS</varname>
+must be enabled for this support.</para>
+</listitem>
+
+<listitem><para>Referencing by device number, offset and length - this
+method extracts addressing information from the name itself. The form
+of the device would be
+<filename>/dev/flash/<replaceable>device-number</replaceable>/<replaceable>offset</replaceable>[,<replaceable>length</replaceable></filename>]</para>
+
+<variablelist>
+<varlistentry><term><replaceable>device-number</replaceable></term>
+
+<listitem><para>This is a fixed number allocated to identify each FLASH
+region in the system. The first region is numbered 0, the second 1,
+and so on. If you have only one FLASH device, it will be numbered 0.
+</para></listitem></varlistentry>
+
+<varlistentry><term><replaceable>offset</replaceable></term>
+<listitem><para>This is the index into the FLASH region in bytes to use. It
+may be specified as decimal, or if prefixed with
+<literal>0x</literal>, then hexadecimal.</para></listitem></varlistentry>
+
+<varlistentry><term><replaceable>length</replaceable></term>
+<listitem><para>This field is optional and defaults to the remainder
+of the FLASH region.  Again it may be specified in decimal or
+hexadecimal.</para></listitem></varlistentry>
+</variablelist>
+
+<para>
+Some examples:
+<variablelist>
+<varlistentry><term>/dev/flash/0/0</term>
+<listitem><para>This defines a block device that uses the entirety of
+FLASH region 0.</para></listitem>
+</varlistentry>
+<varlistentry><term>/dev/flash/1/0x20000,65536</term>
+<listitem><para>This defines a block device which points inside FLASH region 1,
+starting at offset 0x20000 (128Kb) and extending for 64Kb.</para></listitem>
+</varlistentry>
+<varlistentry><term>/dev/flash/0/65536</term>
+<listitem><para>This defines a block device which points inside FLASH region 0,
+starting at offset 64Kb and continuing up to the end of the device.</para></listitem>
+</varlistentry>
+</variablelist>
+</para>
+<para>
+Obviously great care is required when constructing the device names as
+using the wrong specification may subsequently overwrite important areas
+of FLASH, such as RedBoot. Using the alternative via FIS names is
+preferable as these are less error-prone to configure, and also allows for
+the FLASH region to be relocated without requiring program recompilation.
+</para>
+</listitem>
+</orderedlist>
+</SECT1>
+<SECT1 id="ecos-flash-iodevice-usage">
+<TITLE>Using FLASH I/O devices</TITLE>
+<PARA>
+The FLASH I/O block devices can be accessed, read and written using
+the standard interface supplied by the generic I/O
+(<varname>CYGPKG_IO</varname>) package.  These include the functions:
+<function>cyg_io_lookup()</function> to access the device and get a
+handle, <function>cyg_io_read()</function> and
+<function>cyg_io_write()</function> for sequential read and write
+operations, <function>cyg_io_bread()</function> and
+<function>cyg_io_bwrite()</function> for random access read and write
+operations, and <function>cyg_io_get_config()</function> and
+<function>cyg_io_setconfig()</function> for run-time configuration
+inspection and control.
+</PARA>
+<PARA>
+However there are two aspects that differ from some other I/O devices
+accessed this way:
+</para>
+<orderedlist>
+<listitem><para>The first is that the lookup operation uses up
+resources which must be subsequently freed when the last user of the
+I/O handle is finished. The number of FLASH I/O devices that may be
+simultaneously opened is configured with the
+<varname>CYGNUM_IO_FLASH_BLOCK_DEVICES</varname> CDL option. After the
+last user is finished, the device may be closed using
+<function>cyg_io_setconfig()</function> with the
+<varname>CYG_IO_SET_CONFIG_CLOSE</varname> key. Reference counting to
+ensure that it is only the last user that causes a close, is left to
+higher layers.
+</para></listitem>
+<listitem><para>The second is that write operations assume that the
+flash is already erased. Attempting to write to Flash that has
+already been written to may result in errors. Instead FLASH must
+be erased before it may be written.</para></listitem>
+</orderedlist>
+
+<PARA>FLASH block devices can also be read and written using the
+standard POSIX primitives, <function>open()</function>,
+<function>close()</function>, <function>read()</function>,
+<function>write()</function>, <function>lseek()</function>, and so on
+if the POSIX file I/O package (<varname>CYGPKG_FILEIO</varname>) is
+included in the configuration. As with the eCos generic I/O interface
+you must call <function>close()</function> to ensure resources
+are freed when the device is no longer used.</PARA>
+
+<PARA>Other configuration keys are provided to perform FLASH erase
+operations, and to retrieve device sizes, and FLASH block sizes at
+a particular address. These operations are accessed with
+<function>cyg_io_get_config()</function> (or if using the POSIX
+file I/O API, <function>cyg_fs_getinfo()</function>) with the
+following keys:</para>
+
+<variablelist>
+<varlistentry><term><varname>CYG_IO_GET_CONFIG_FLASH_ERASE</varname></term>
+<listitem><para>This erases a region of FLASH.
+<function>cyg_io_get_config()</function> must be passed a
+structure defined as per the following, which is also supplied
+in <filename>&lt;cyg/io/flash.h&gt;</filename>:
+<programlisting>
+typedef struct {
+    CYG_ADDRESS offset;
+    size_t len;
+    int flasherr;
+    cyg_flashaddr_t err_address;
+} cyg_io_flash_getconfig_erase_t;
+</programlisting>
+</para>
+<para> In this structure, <structfield>offset</structfield> specifies
+the offset within the block device to erase, <structfield>len</structfield>
+specifies the amount to address, <structfield>flasherr</structfield> is
+set on return to specify an error with the FLASH erase operation itself,
+and <structfield>err_address</structfield> is used if there was an error
+to specify at which address the error happened.</para>
+</listitem></varlistentry>
+
+<varlistentry><term><varname>CYG_IO_GET_CONFIG_FLASH_LOCK</varname></term>
+<listitem><para>This protects a region of FLASH using the locking facilities
+available on the card, if provided by the underlying driver. 
+<function>cyg_io_get_config()</function> must be passed a
+structure defined as per the following:
+<programlisting>
+typedef struct {
+    CYG_ADDRESS offset;
+    size_t len;
+    int flasherr;
+    cyg_flashaddr_t err_address;
+} cyg_io_flash_getconfig_lock_t;
+</programlisting>
+</para>
+<para> In this structure, <structfield>offset</structfield> specifies
+the offset within the block device to lock, <structfield>len</structfield>
+specifies the amount to address, <structfield>flasherr</structfield> is
+set on return to specify an error with the FLASH lock operation itself,
+and <structfield>err_address</structfield> is used if there was an error
+to specify at which address the error happened. If locking
+support is not available -EINVAL will be returned from
+<function>cyg_io_get_config()</function>.</para>
+</listitem></varlistentry>
+
+<varlistentry><term><varname>CYG_IO_GET_CONFIG_FLASH_UNLOCK</varname></term>
+<listitem><para>This disables protection for a region of FLASH using the
+unlocking facilities available on the card, if provided by the underlying driver. 
+<function>cyg_io_get_config()</function> must be passed a
+structure defined as per the following:
+<programlisting>
+typedef struct {
+    CYG_ADDRESS offset;
+    size_t len;
+    int flasherr;
+    cyg_flashaddr_t err_address;
+} cyg_io_flash_getconfig_unlock_t;
+</programlisting>
+</para>
+<para> In this structure, <structfield>offset</structfield> specifies
+the offset within the block device to unlock, <structfield>len</structfield>
+specifies the amount to address, <structfield>flasherr</structfield> is
+set on return to specify an error with the FLASH unlock operation itself,
+and <structfield>err_address</structfield> is used if there was an error
+to specify at which address the error happened. If unlocking
+support is not available -EINVAL will be returned from
+<function>cyg_io_get_config()</function>.</para>
+</listitem></varlistentry>
+
+<varlistentry><term><varname>CYG_IO_GET_CONFIG_FLASH_DEVSIZE</varname></term>
+<listitem><para>This returns the size of the FLASH block device. The
+<function>cyg_io_get_config()</function> function must be passed a
+structure defined as per the following, which is also supplied
+in <filename>&lt;cyg/io/flash.h&gt;</filename>:
+<programlisting>
+typedef struct {
+    size_t dev_size;
+} cyg_io_flash_getconfig_devsize_t;
+</programlisting>
+</para>
+<para> In this structure, <structfield>dev_size</structfield> is used to
+return the size of the FLASH device.</para>
+</listitem></varlistentry>
+
+<varlistentry><term><varname>CYG_IO_GET_CONFIG_FLASH_DEVADDR</varname></term>
+<listitem><para>This returns the address in the virtual memory map that the
+generic flash layer has been informed that this FLASH device is mapped to. Note
+that some flash devices such as dataflash are not truly memory mapped,
+and so this function only returns useful information when used with a true
+memory mapped FLASH device. The
+<function>cyg_io_get_config()</function> function must be passed a
+structure defined as per the following, which is also supplied
+in <filename>&lt;cyg/io/flash.h&gt;</filename>:
+<programlisting>
+typedef struct {
+    cyg_flashaddr_t dev_addr;
+} cyg_io_flash_getconfig_devaddr_t;
+</programlisting>
+</para>
+<para> In this structure, <structfield>dev_addr</structfield> is used to
+return the address corresponding to the base of the FLASH device in the
+virtual memory map.</para>
+</listitem></varlistentry>
+
+<varlistentry><term><varname>CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE</varname></term>
+<listitem><para>This returns the size of a FLASH block at a
+supplied offset in the FLASH block device. The
+<function>cyg_io_get_config()</function> function must be passed a
+structure defined as per the following, which is also supplied
+in <filename>&lt;cyg/io/flash.h&gt;</filename>:
+<programlisting>
+typedef struct {
+    CYG_ADDRESS offset;
+    size_t block_size;
+} cyg_io_flash_getconfig_blocksize_t;
+</programlisting>
+</para>
+<para> In this structure, <structfield>offset</structfield> specifies the
+address within the block device of which the FLASH block size is
+required - a single FLASH device may contain blocks of differing
+sizes. The <structfield>block_size</structfield> field is used to
+return the block size at the specified offset.</para>
+</listitem></varlistentry>
+</variablelist>
+</SECT1>
+</CHAPTER>
 </PART>
Index: packages/io/flash/current/include/flash.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/include/flash.h,v
retrieving revision 1.18
diff -u -5 -p -r1.18 flash.h
--- packages/io/flash/current/include/flash.h	24 Nov 2003 12:18:33 -0000	1.18
+++ packages/io/flash/current/include/flash.h	18 Nov 2008 00:54:13 -0000
@@ -6,12 +6,14 @@
 //
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2004, 2005 eCosCentric Ltd.
 // Copyright (C) 2003 Gary Thomas
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -40,11 +42,11 @@
 //####ECOSGPLCOPYRIGHTEND####
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, Andrew Lunn, bartv
 // Date:         2000-07-14
 // Purpose:      
 // Description:  
 //              
 //####DESCRIPTIONEND####
@@ -52,190 +54,147 @@
 //==========================================================================
 
 #ifndef _IO_FLASH_H_
 #define _IO_FLASH_H_
 
+#include <pkgconf/system.h>
 #include <pkgconf/io_flash.h>
-#include <cyg/hal/hal_cache.h>
+#include <stddef.h>
+#include <cyg/infra/cyg_type.h>
+#ifdef CYGPKG_KERNEL
+#include <cyg/kernel/kapi.h>
+#endif
+
+// Currently a 32-bit quantity. In future this may be 64-bits on some
+// platforms, e.g. to support very large nand flashes which can only
+// be accessed indirectly.
+typedef CYG_ADDRESS cyg_flashaddr_t;
+
+typedef struct cyg_flash_block_info 
+{
+  size_t                    block_size;
+  cyg_uint32                blocks;
+} cyg_flash_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
+  const cyg_flash_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(const cyg_flashaddr_t flash_base, 
+                                      cyg_flash_info_t * info);
+__externC int cyg_flash_verify_addr(const cyg_flashaddr_t address);
+__externC size_t cyg_flash_block_size(const cyg_flashaddr_t flash_base);
+__externC int cyg_flash_read(const cyg_flashaddr_t flash_base, 
+                             void *ram_base, 
+                             size_t len, 
+                             cyg_flashaddr_t *err_address);
+__externC int cyg_flash_erase(cyg_flashaddr_t flash_base, 
+                              size_t len, 
+                              cyg_flashaddr_t *err_address);
+__externC int cyg_flash_program(cyg_flashaddr_t flash_base, 
+                                const void *ram_base, 
+                                size_t len, 
+                                cyg_flashaddr_t *err_address);
+__externC int cyg_flash_lock(const cyg_flashaddr_t flash_base, 
+                             size_t len, 
+                             cyg_flashaddr_t *err_address);
+__externC int cyg_flash_unlock(const cyg_flashaddr_t flash_base, 
+                               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, 
+                                   size_t len);
+__externC int cyg_flash_mutex_unlock(const cyg_flashaddr_t from, 
+                                     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);
 externC int flash_unlock(void *base, int len, void **err_address);
 #endif
 externC int flash_verify_addr(void *base);
 externC int flash_get_limits(void *base, void **start, void **end);
 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(CYGHWR_IO_FLASH_DEVICE_LEGACY)
+#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
+#if defined(CYGPKG_IO_FLASH_BLOCK_DEVICE) || \
+      defined(CYGPKG_IO_FLASH_BLOCK_DEVICE_LEGACY)
 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 cyg_io_flash_getconfig_erase_t cyg_io_flash_getconfig_lock_t;
+typedef cyg_io_flash_getconfig_erase_t cyg_io_flash_getconfig_unlock_t;
+
 typedef struct {
-    int dev_size;
+    size_t dev_size;
 } cyg_io_flash_getconfig_devsize_t;
 
 typedef struct {
+    cyg_flashaddr_t dev_addr;
+} cyg_io_flash_getconfig_devaddr_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);
-#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_
Index: packages/io/flash/current/include/flash_dev.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/include/flash_dev.h,v
retrieving revision 1.6
diff -u -5 -p -r1.6 flash_dev.h
--- packages/io/flash/current/include/flash_dev.h	14 Apr 2003 11:59:19 -0000	1.6
+++ packages/io/flash/current/include/flash_dev.h	18 Nov 2008 00:54:13 -0000
@@ -8,10 +8,13 @@
 //
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Ltd.
+// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2003 Gary Thomas
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
@@ -40,10 +43,148 @@
 // -------------------------------------------
 //####ECOSGPLCOPYRIGHTEND####
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
+// Author(s):    gthomas
+// Contributors: gthomas, Andrew Lunn, bartv
+// Date:         2000-07-14
+// Purpose:      
+// Description:  
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/io_flash.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/io/flash.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_tables.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, size_t len);
+  int     (*flash_erase_block) (struct cyg_flash_dev *dev, 
+                                cyg_flashaddr_t block_base);
+  int     (*flash_program) (struct cyg_flash_dev *dev, 
+                            cyg_flashaddr_t base, 
+                            const void* data, size_t len);
+  int     (*flash_read) (struct cyg_flash_dev *dev, 
+                         const cyg_flashaddr_t base, 
+                         void* data, size_t len);
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING    
+  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);
+#endif    
+};
+
+// Dummy functions for some of the above operations, if a device does
+// not support e.g. locking.
+externC int     cyg_flash_devfn_init_nop(struct cyg_flash_dev*);
+externC size_t  cyg_flash_devfn_query_nop(struct cyg_flash_dev*, void*, const size_t);
+externC int     cyg_flash_devfn_lock_nop(struct cyg_flash_dev*, const cyg_flashaddr_t);
+externC int     cyg_flash_devfn_unlock_nop(struct cyg_flash_dev*, const cyg_flashaddr_t);
+
+// Facilitate function calls between flash-resident code and .2ram
+// functions.
+externC void*   cyg_flash_anonymizer(void*);
+
+// Structure each device places in the HAL table
+struct cyg_flash_dev {
+  const struct cyg_flash_dev_funs *funs;            // Function pointers
+  cyg_uint32                      flags;            // Device characteristics
+  cyg_flashaddr_t                 start;            // First address
+  cyg_flashaddr_t                 end;              // Last address
+  cyg_uint32                      num_block_infos;  // Number of entries
+  const cyg_flash_block_info_t    *block_info;      // Info about one block size
+
+  const void                      *priv;            // Devices private data
+
+  // 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
+#if (CYGHWR_IO_FLASH_DEVICE > 1)    
+  struct cyg_flash_dev            *next;            // Pointer to next device
+#endif    
+} CYG_HAL_TABLE_TYPE;
+
+// Macros for instantiating the above structures.
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+# define CYG_FLASH_FUNS(_funs_, _init_, _query_ , _erase_, _prog_ , _read_, _lock_, _unlock_) \
+struct cyg_flash_dev_funs _funs_ =      \
+{										\
+	.flash_init             = _init_,   \
+	.flash_query            = _query_,  \
+	.flash_erase_block      = _erase_,  \
+	.flash_program          = _prog_,   \
+	.flash_read             = _read_,   \
+	.flash_block_lock       = _lock_,   \
+	.flash_block_unlock     = _unlock_  \
+}
+#else
+# define CYG_FLASH_FUNS(_funs_, _init_, _query_ , _erase_, _prog_ , _read_, _lock_, _unlock_) \
+struct cyg_flash_dev_funs _funs_ =      \
+{										\
+	.flash_init             = _init_,   \
+	.flash_query            = _query_,  \
+	.flash_erase_block      = _erase_,  \
+	.flash_program          = _prog_,   \
+	.flash_read             = _read_    \
+}
+#endif
+
+// We assume HAL tables are placed into RAM.
+#define CYG_FLASH_DRIVER(_name_, _funs_, _flags_, _start_, _end_, _num_block_infos_, _block_info_, _priv_)  \
+struct cyg_flash_dev _name_ CYG_HAL_TABLE_ENTRY(cyg_flashdev) = \
+{                                                               \
+    .funs               = _funs_,                               \
+    .flags              = _flags_,                              \
+    .start              = _start_,                              \
+    .end                = _end_,                                \
+    .num_block_infos    = _num_block_infos_,                    \
+    .block_info         = _block_info_,                         \
+    .priv               = _priv_                                \
+}
+
+// Additional support for legacy device drivers.
+#ifdef CYGHWR_IO_FLASH_DEVICE_LEGACY
+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 // CYGHWR_IO_FLASH_DEVICE_LEGACY
+
+// ----------------------------------------------------------------------------
+// This section provides utility macros used by some flash drivers, especially
+// the legacy ones. Such flash drivers need to #define _FLASH_PRIVATE before
+// including this file.
+
+#ifdef _FLASH_PRIVATE_
+
+//==========================================================================
 // Author(s):    hmt
 // Contributors: hmt, jskov, Jose Pascual <josepascual@almudi.com>
 // Date:         2001-02-22
 // Purpose:      Define common flash device driver definitions
 // Description:  The flash_data_t type is used for accessing
@@ -51,20 +192,12 @@
 //               The FLASHWORD macro must be used to create constants
 //               of suitable width.
 //               The FLASH_P2V macro can be used to fix up non-linear
 //               mappings of flash blocks (defaults to a linear 
 //               implementation).
-//              
-//####DESCRIPTIONEND####
-//
 //==========================================================================
 
-#ifdef _FLASH_PRIVATE_
-#include <cyg/infra/cyg_type.h>
-
-// ------------------------------------------------------------------------
-//
 // No mapping on this target - but these casts would be needed if some
 // manipulation did occur.  An example of this might be:
 // // First 4K page of flash at physical address zero is
 // // virtually mapped at address 0xa0000000.
 // #define FLASH_P2V(x) ((volatile flash_t *)(((unsigned)(x) < 0x1000) ?
@@ -163,5 +296,6 @@ typedef cyg_uint64 flash_data_t;
 #endif // _FLASH_PRIVATE_
 
 #endif // CYGONCE_IO_FLASH_FLASH_DEV_H
 //----------------------------------------------------------------------------
 // end of flash_dev.h
+
Index: packages/io/flash/current/src/flash.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/src/flash.c,v
retrieving revision 1.27
diff -u -5 -p -r1.27 flash.c
--- packages/io/flash/current/src/flash.c	25 Feb 2006 14:07:43 -0000	1.27
+++ packages/io/flash/current/src/flash.c	18 Nov 2008 00:54:13 -0000
@@ -6,12 +6,14 @@
 //
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2004, 2005, 2006 eCosCentric Ltd.
 // Copyright (C) 2003 Gary Thomas
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -31,530 +33,899 @@
 // 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
+// Contributors: gthomas, Andrew Lunn, Bart Veer
 // Date:         2000-07-26
 // Purpose:      
 // Description:  
 //              
 //####DESCRIPTIONEND####
 //
 //==========================================================================
 
 #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>
+#include <cyg/io/flash_dev.h>
+#include "flash_legacy.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*);
-
-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;
-
-int
-flash_init(_printf *pf)
-{
-    int err;
-
-    flash_info.pf = pf; // Do this before calling into the driver
-    if (flash_info.init) return FLASH_ERR_OK;
-
-    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;
-}
-
-// 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;
-}
-
-// 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)
-{
-    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);
-}
-
-int
-flash_verify_addr(void *target)
-{
-    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;
-    }
-}
-
-int
-flash_get_limits(void *target, void **start, void **end)
-{
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-    *start = flash_info.start;
-    *end = flash_info.end;
-    return FLASH_ERR_OK;
-}
-
-int
-flash_get_block_info(int *block_size, int *blocks)
-{
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
-    *block_size = flash_info.block_size;
-    *blocks = flash_info.blocks;
-    return FLASH_ERR_OK;
-}
-
-int
-flash_erase(void *addr, int len, void **err_addr)
-{
-    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;
-    }
-
-#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);
-
-    /* Check to see if end_addr overflowed */
-    if( (end_addr < block) && (len > 0) ){
-        end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
-    }
-
+// Optional verbosity. Using a macro here avoids lots of ifdefs in the
+// rest of the code.
 #ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.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) {
-        // 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;
-            }
-        }
+# define CHATTER(_dev_, _fmt_, ...) (*(_dev_)->pf)((_fmt_), ## __VA_ARGS__)
 #else
-        bool erased = false;
+# define CHATTER(_dev_, _fmt_, ...) CYG_EMPTY_STATEMENT
 #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;
-        }
-
-        // 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;
-        }
-#ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
-#endif
-    }
-    FLASH_Disable(block, end_addr);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
+// Per-thread locking. Again using macros avoids lots of ifdefs
+#ifdef CYGPKG_KERNEL
+# define LOCK_INIT(_dev_)   cyg_mutex_init(&((_dev_)->mutex))
+# define LOCK(_dev_)        cyg_mutex_lock(&((_dev_)->mutex))
+# define UNLOCK(_dev_)      cyg_mutex_unlock(&((_dev_)->mutex))
+#else
+# define LOCK_INIT(_dev_)   CYG_EMPTY_STATEMENT
+# define LOCK(_dev_)        CYG_EMPTY_STATEMENT
+# define UNLOCK(_dev_)      CYG_EMPTY_STATEMENT
 #endif
-    return (stat);
-}
-
-int
-flash_program(void *_addr, void *_data, int len, void **err_addr)
-{
-    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;
-    }
 
+// Software write-protect. Very rarely used.
 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-    if (plf_flash_query_soft_wp(addr,len))
-        return FLASH_ERR_PROTECT;
-#endif
-
-    _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf);
-
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data, 
-                     (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
+# define CHECK_SOFT_WRITE_PROTECT(_addr_, _len_)    \
+  CYG_MACRO_START                                   \
+  if (plf_flash_query_soft_wp((_addr_), (_len_)))   \
+    return CYG_FLASH_ERR_PROTECT;                   \
+  CYG_MACRO_END
+#else
+#define CHECK_SOFT_WRITE_PROTECT(_addr_, _len_) CYG_EMPTY_STATEMENT
 #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;
-
-        }
+// Has the FLASH IO library been initialised?
+static bool init;
 
-        stat = (*_flash_program_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 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)(".");
-#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);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
-#endif
-    return (stat);
+// 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);
+
+#if (1 == CYGHWR_IO_FLASH_DEVICE)
+
+// Optimize the code for a single flash device, which is the common case.
+// The flash subsystem must have been initialized, the single device must
+// contain the specified address, and the device itself must have
+// initialized successfully.
+static struct cyg_flash_dev*
+find_dev(cyg_flashaddr_t addr, int* stat)
+{
+  if (!init) {
+    *stat = CYG_FLASH_ERR_NOT_INIT;
+    return NULL;
+  }
+  if (! ((addr >= cyg_flashdevtab[0].start) && (addr <= cyg_flashdevtab[0].end))) {
+    *stat = CYG_FLASH_ERR_INVALID;
+    return NULL;
+  }
+  if (! cyg_flashdevtab[0].init) {
+    *stat = CYG_FLASH_ERR_NOT_INIT;
+    return NULL;
+  }
+  return &cyg_flashdevtab[0];
 }
 
-int
-flash_read(void *_addr, void *_data, int len, void **err_addr)
-{
-#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);
+#else
 
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("... Read from %p-%p at %p: ", (void*)data, 
-                     (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
+// There are multiple devices. For convenience these are kept in a
+// linked list, sorted by address. This is the head of the list
+static struct cyg_flash_dev *flash_head = NULL;
+
+static bool flash_sort_and_check(void) 
+{
+  bool moved;
+  struct cyg_flash_dev *dev, **previous_next;
+
+  // Place all devices that initialised on the list, unsorted for now.
+  for (dev = &cyg_flashdevtab[0]; dev != &cyg_flashdevtab_end; dev++) {
+    if (dev->init) {
+      dev->next  = flash_head;
+      flash_head = dev;
+    }
+  }
+  
+  // If there are no valid devices, abort. This might happen if
+  // all drivers failed to initialize.
+  if (flash_head == NULL) {
+    return false;
+  }
+
+  // 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. This loop may run safely with just one
+  // entry on the list.
+  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);
+  
+  // Now walk the linked list and see if there are any overlaps in the
+  // addresses the devices claim to use using.
+  for (dev=flash_head; dev->next; dev=dev->next){
+    if (dev->end >= dev->next->start)
+      return false;
+  }
+  return true;
+}
+
+// Find the device at the specified address, if any.
+static struct cyg_flash_dev*
+find_dev(cyg_flashaddr_t addr, int* stat)
+{
+  struct cyg_flash_dev*   dev;
+  if (!init) {
+    *stat = CYG_FLASH_ERR_NOT_INIT;
+    return NULL;
+  }
+  for (dev = flash_head; dev; dev = dev->next) {
+    if ((dev->start <= addr) && (addr <= dev->end)) {
+      return dev;
+    }
+  }
+  *stat = CYG_FLASH_ERR_INVALID;
+  return NULL;
+}
+
+#endif
+
+// 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) 
+{
+  int err;
+  struct cyg_flash_dev * dev;
+  
+  if (init) return CYG_FLASH_ERR_OK;
+
+  CYG_ASSERT(&(cyg_flashdevtab[CYGHWR_IO_FLASH_DEVICE]) == &cyg_flashdevtab_end, "incorrect number of flash devices");
+  
+  for (dev = &cyg_flashdevtab[0]; dev != &cyg_flashdevtab_end; dev++) {
+    dev->pf = pf;
+    LOCK_INIT(dev);
+    
+    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 infos");
+    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");
+#ifdef CYGDBG_USE_ASSERTS
+    {
+         int i; 
+         cyg_flashaddr_t addr = dev->start;
+         for (i = 0; i < dev->num_block_infos; i++) {
+              addr += dev->block_info[i].block_size * dev->block_info[i].blocks;
+         }
+         CYG_ASSERT(dev->end == addr-1, "Invalid end address");
+    }
+#endif
+    dev->init = true;
+  }
+  
+#if (1 == CYGHWR_IO_FLASH_DEVICE)
+  // Make sure there is one device, otherwise we could end up
+  // accessing a non-existent cyg_flash_dev structure.
+  if (&(cyg_flashdevtab[0]) == &cyg_flashdevtab_end) {
+      return CYG_FLASH_ERR_INVALID;
+  }
+#else
+  // Place the devices on a sorted linked list and check that there
+  // are no overlaps in the address space.
+  if (! flash_sort_and_check() ) {
+    return CYG_FLASH_ERR_INVALID;
+  }
 #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_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 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)(".");
-#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);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
-#endif
-    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
+  // Only mark the flash subsystem as initialized if the world is
+  // consistent.
+  init = true;
+  return CYG_FLASH_ERR_OK;
 }
 
-#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
-
-int
-flash_lock(void *addr, int len, void **err_addr)
+// Is the address within one of the flash drivers?
+__externC int
+cyg_flash_verify_addr(const cyg_flashaddr_t 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;
-    }
-
-#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
-    if (plf_flash_query_soft_wp(addr,len))
-        return FLASH_ERR_PROTECT;
-#endif
-
-    _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_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)("... Lock from %p-%p: ", block, end_addr);
-#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;
-        }
-#ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
-#endif
-    }
-    FLASH_Disable(block, end_addr);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
-#endif
-    return (stat);
+  int stat = CYG_FLASH_ERR_OK;
+  (void) find_dev(address, &stat);
+  return stat;
 }
 
-int
-flash_unlock(void *addr, int len, void **err_addr)
+// Return information about the Nth driver
+__externC int
+cyg_flash_get_info(cyg_uint32 Nth, cyg_flash_info_t * info)
 {
-    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;
+  struct cyg_flash_dev * dev;
 
-    if (!flash_info.init) {
-        return FLASH_ERR_NOT_INIT;
-    }
+  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;
-#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);
-#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;
-        }
-#ifdef CYGSEM_IO_FLASH_CHATTER
-        (*flash_info.pf)(".");
-#endif
+#if (1 == CYGHWR_IO_FLASH_DEVICE)
+  if ((0 == Nth) && cyg_flashdevtab[0].init) {
+      dev = &(cyg_flashdevtab[0]);
+  } else {
+      return CYG_FLASH_ERR_INVALID;
+  }
+#else
+  // Only initialized devices are on the list.
+  for (dev = flash_head; dev && Nth; dev=dev->next, Nth--)
+    ;
+  if (!dev) {
+      return CYG_FLASH_ERR_INVALID;
+  }
+#endif
+  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 information about the flash at the given address
+__externC int
+cyg_flash_get_info_addr(const cyg_flashaddr_t flash_base, cyg_flash_info_t * info)
+{
+  struct cyg_flash_dev *dev;
+  int                   stat = CYG_FLASH_ERR_OK;
+
+  dev = find_dev(flash_base, &stat);
+  if (dev) {
+    info->start = dev->start;
+    info->end = dev->end;
+    info->num_block_infos = dev->num_block_infos;
+    info->block_info = dev->block_info;
+  }
+  return stat;
+}
+
+#ifdef CYGPKG_KERNEL
+// Lock the mutex's for a range of addresses
+__externC int
+cyg_flash_mutex_lock(const cyg_flashaddr_t from, size_t len) 
+{
+  struct cyg_flash_dev *    dev;
+  int                       stat    = CYG_FLASH_ERR_OK;
+
+  dev = find_dev(from, &stat);
+  if (dev) {
+    LOCK(dev);
+    if (len > (dev->end + 1 - from)) {
+      stat = cyg_flash_mutex_lock(dev->end + 1, len - (dev->end + 1 - from));
+      if (CYG_FLASH_ERR_OK != stat) {
+        // Something went wrong, unlock what we just locked
+        UNLOCK(dev);
+      }
+    }
+  }
+  return stat;
+}
+
+// Unlock the mutex's for a range of addresses
+__externC int
+cyg_flash_mutex_unlock(const cyg_flashaddr_t from, size_t len) 
+{
+  struct cyg_flash_dev *    dev;
+  int                       stat = CYG_FLASH_ERR_OK;
+
+  dev = find_dev(from, &stat);
+  if (dev) {
+    UNLOCK(dev);
+    if (len > (dev->end + 1 - from)) {
+      stat = cyg_flash_mutex_lock(dev->end + 1, len - (dev->end + 1 - from));
+      if (CYG_FLASH_ERR_OK != stat) {
+        // Something went wrong, relock what we just unlocked. This may not
+        // be worth it since things must be pretty messed up, and could
+        // conceivably end in deadlock if there is a concurrent call to
+        // cyg_flash_mutex_lock();
+        LOCK(dev);
+      }
+    }
+  }
+  return stat;
+}
+#endif
+
+// 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;
+  int                       stat;
+
+  dev = find_dev(flash_base, &stat);
+  if (!dev) return stat;
+  return flash_block_size(dev, flash_base);
+}
+
+// Return the first address of a block. The flash might not be aligned
+// in terms of its block size. So we have to be careful and use
+// offsets.
+static inline cyg_flashaddr_t 
+flash_block_begin(cyg_flashaddr_t addr, struct cyg_flash_dev *dev)
+{
+  size_t block_size;
+  cyg_flashaddr_t offset;
+  
+  block_size = flash_block_size(dev, addr);
+  
+  offset = addr - dev->start;
+  offset = (offset / block_size) * block_size;
+  return offset + dev->start;
+}
+
+
+__externC int 
+cyg_flash_erase(cyg_flashaddr_t flash_base, 
+                size_t len, 
+                cyg_flashaddr_t *err_address)
+{
+  cyg_flashaddr_t block, end_addr;
+  struct cyg_flash_dev * dev;
+  size_t erase_count;
+  int stat = CYG_FLASH_ERR_OK;
+  HAL_FLASH_CACHES_STATE(d_cache, i_cache);
+
+  dev = find_dev(flash_base, &stat);
+  if (!dev) return stat;
+
+  CHECK_SOFT_WRITE_PROTECT(flash_base, len);
+  
+  LOCK(dev);
+
+  // Check whether or not we are going past the end of this device, on
+  // to the next one. If so the next device will be handled by a
+  // recursive call later on.
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
+  }
+  // erase can only happen on a block boundary, so adjust for this
+  block         = flash_block_begin(flash_base, dev);
+  erase_count   = (end_addr + 1) - block;
+
+  CHATTER(dev, "... Erase from %p-%p: ", (void*)block, (void*)end_addr);
+  
+  HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+  FLASH_Enable(flash_base, end_addr);
+  while (erase_count > 0) {
+    int i;
+    unsigned char *dp;
+    bool erased = false;
+    size_t block_size = flash_block_size(dev, block);
+
+    // Pad to the block boundary, if necessary
+    if (erase_count < block_size) {
+        erase_count = block_size;
+    }
+
+    // If there is a read function it probably means the flash
+    // cannot be read directly.
+    if (!dev->funs->flash_read) {
+      erased = true;
+      dp = (unsigned char *)block;
+      for (i = 0;  i < block_size;  i++) {
+        if (*dp++ != (unsigned char)0xFF) {
+          erased = false;
+          break;
+        }
+      }
+    }
+    if (!erased) {
+      stat = dev->funs->flash_erase_block(dev,block);
+    }
+    if (CYG_FLASH_ERR_OK != stat) {
+        if (err_address)
+            *err_address = block;
+        break;
+    }
+    block       += block_size;
+    erase_count -= block_size;
+    CHATTER(dev, ".");
+  }
+  FLASH_Disable(flash_base, end_addr);
+  HAL_FLASH_CACHES_ON(d_cache, i_cache);
+  CHATTER(dev, "\n");
+  UNLOCK(dev);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return stat;
+  }
+
+  // If there are multiple flash devices in series the erase operation
+  // may touch successive devices. This can be handled by recursion.
+  // The stack overheads should be minimal because the number of
+  // devices will be small.
+  if (len > (dev->end + 1 - flash_base)) {
+    return cyg_flash_erase(dev->end+1, 
+                           len - (dev->end + 1 - flash_base),
+                           err_address);
+  }
+  return CYG_FLASH_ERR_OK;
+}
+
+__externC int 
+cyg_flash_program(cyg_flashaddr_t flash_base, 
+                  const void *ram_base, 
+                  size_t len, 
+                  cyg_flashaddr_t *err_address)
+{
+  struct cyg_flash_dev * dev;
+  cyg_flashaddr_t addr, end_addr, block;
+  const unsigned char * ram = ram_base;
+  size_t write_count, offset;
+  int stat = CYG_FLASH_ERR_OK;
+  HAL_FLASH_CACHES_STATE(d_cache, i_cache);
+
+  dev = find_dev(flash_base, &stat);
+  if (!dev) return stat;
+
+  CHECK_SOFT_WRITE_PROTECT(flash_base, len);
+  
+  LOCK(dev);
+  addr = flash_base;
+  if (len > (dev->end + 1 - flash_base)) {
+    end_addr = dev->end;
+  } else {
+    end_addr = flash_base + len - 1;
+  }
+  write_count = (end_addr + 1) - flash_base;
+
+  // The first write may be in the middle of a block. Do the necessary
+  // adjustment here rather than inside the loop.
+  block = flash_block_begin(flash_base, dev);
+  if (addr == block) {
+      offset = 0;
+  } else {
+      offset = addr - block;
+  }
+  
+  CHATTER(dev, "... Program from %p-%p to %p: ", ram_base, ((CYG_ADDRESS)ram_base)+write_count, addr);
+  
+  HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+  FLASH_Enable(flash_base, end_addr);
+  while (write_count > 0) {
+    size_t block_size = flash_block_size(dev, addr);
+    size_t this_write;
+    if (write_count > (block_size - offset)) {
+        this_write = block_size - offset;
+    } else {
+        this_write = write_count;
     }
-    FLASH_Disable(block, end_addr);
-    HAL_FLASH_CACHES_ON(d_cache, i_cache);
-#ifdef CYGSEM_IO_FLASH_CHATTER
-    (*flash_info.pf)("\n");
-#endif
+    // Only the first block may need the offset.
+    offset       = 0;
+    
+    stat = dev->funs->flash_program(dev, addr, ram, this_write);
+#ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
+    if (CYG_FLASH_ERR_OK == stat) // Claims to be OK
+      if (!dev->funs->flash_read && memcmp((void *)addr, ram, this_write) != 0) {                
+        stat = CYG_FLASH_ERR_DRV_VERIFY;
+        CHATTER(dev, "V");
+      }
+#endif
+    if (CYG_FLASH_ERR_OK != stat) {
+        if (err_address)
+            *err_address = addr;
+        break;
+    }
+    CHATTER(dev, ".");
+    write_count -= this_write;
+    addr        += this_write;
+    ram         += this_write;
+  }
+  FLASH_Disable(flash_base, end_addr);
+  HAL_FLASH_CACHES_ON(d_cache, i_cache);
+  CHATTER(dev, "\n");
+  UNLOCK(dev);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return (stat);
+  }
+  if (len > (dev->end + 1 - flash_base)) {
+    return cyg_flash_program(dev->end+1, ram, 
+                             len - (dev->end + 1 - flash_base),
+                             err_address);
+  }
+  return CYG_FLASH_ERR_OK;
+}
+
+__externC int 
+cyg_flash_read(const cyg_flashaddr_t flash_base, 
+               void *ram_base, 
+               size_t len, 
+               cyg_flashaddr_t *err_address)
+{
+  struct cyg_flash_dev * dev;
+  cyg_flashaddr_t addr, end_addr;
+  unsigned char * ram = (unsigned char *)ram_base;
+  size_t read_count;
+  int stat = CYG_FLASH_ERR_OK;
+
+  dev = find_dev(flash_base, &stat);
+  if (!dev) return stat;
+
+  LOCK(dev);
+  addr = flash_base;
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
+  }
+  read_count = (end_addr + 1) - flash_base;
+
+  //  CHATTER(dev, "... Read from %p-%p to %p: ", addr, end_addr, ram_base);
+
+  // If the flash is directly accessible, just read it in one go. This
+  // still happens with the mutex locked to protect against concurrent
+  // programs/erases.
+  if (! dev->funs->flash_read) {
+      memcpy(ram, (void*)addr, read_count);
+  } else {
+#ifndef CYGHWR_IO_FLASH_INDIRECT_READS
+      CYG_FAIL("read function supplied but indirect reads not enabled");
+      stat = CYG_FLASH_ERR_PROTOCOL;
+      if (err_address) {
+          *err_address = addr;
+      }
+#else
+      // We have to indirect through the device driver.
+      // The first read may be in the middle of a block. Do the necessary
+      // adjustment here rather than inside the loop.
+      size_t            offset;
+      cyg_flashaddr_t   block = flash_block_begin(flash_base, dev);
+      HAL_FLASH_CACHES_STATE(d_cache, i_cache);
+      if (addr == block) {
+          offset = 0;
+      } else {
+          offset = addr - block;
+      }
+      HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+      FLASH_Enable(flash_base, end_addr);
+      while (read_count > 0) {
+          size_t block_size = flash_block_size(dev, addr);
+          size_t this_read;
+          if (read_count > (block_size - offset)) {
+              this_read = block_size - offset;
+          } else {
+              this_read = read_count;
+          }
+          // Only the first block may need the offset
+          offset      = 0;
+    
+          stat = dev->funs->flash_read(dev, addr, ram, this_read);
+          if (CYG_FLASH_ERR_OK != stat && err_address) {
+              *err_address = addr;
+              break;
+          }
+          //          CHATTER(dev, ".");
+          read_count  -= this_read;
+          addr        += this_read;
+          ram         += this_read;
+      }
+      FLASH_Disable(flash_base, end_addr);
+      HAL_FLASH_CACHES_ON(d_cache, i_cache);
+#endif      
+  }
+  //  CHATTER(dev, "\n");
+  UNLOCK(dev);
+  if (stat != CYG_FLASH_ERR_OK) {
     return (stat);
+  }
+  if (len > (dev->end + 1 - flash_base)) {
+      return cyg_flash_read(dev->end+1, ram,
+                            len - (dev->end + 1 - flash_base),
+                            err_address);
+  }
+  return CYG_FLASH_ERR_OK;
+}
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+__externC int 
+cyg_flash_lock(const cyg_flashaddr_t flash_base, 
+               size_t len, 
+               cyg_flashaddr_t *err_address)
+{
+  cyg_flashaddr_t block, end_addr;
+  struct cyg_flash_dev * dev;
+  size_t lock_count;
+  int stat = CYG_FLASH_ERR_OK;
+  HAL_FLASH_CACHES_STATE(d_cache, i_cache);
+
+  dev = find_dev(flash_base, &stat);
+  if (!dev) return stat;
+  if (!dev->funs->flash_block_lock) return CYG_FLASH_ERR_INVALID;
+
+  CHECK_SOFT_WRITE_PROTECT(flash_base, len);
+  
+  LOCK(dev);
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
+  }
+  block         = flash_block_begin(flash_base, dev);
+  lock_count    = (end_addr + 1) - block;
+  
+  CHATTER(dev, "... Locking from %p-%p: ", (void*)block, (void*)end_addr);
+  
+  HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+  FLASH_Enable(flash_base, end_addr);
+  while (lock_count > 0) {
+    size_t  block_size  = flash_block_size(dev, block);
+    if (lock_count < block_size) {
+        lock_count = block_size;
+    }
+    stat = dev->funs->flash_block_lock(dev,block);
+    
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = block;
+      break;
+    }
+    block       += block_size;
+    lock_count  -= block_size;
+    CHATTER(dev, ".");
+  }
+  FLASH_Disable(flash_base, end_addr);
+  HAL_FLASH_CACHES_ON(d_cache, i_cache);
+  CHATTER(dev, "\n");
+  UNLOCK(dev);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return stat;
+  }
+
+  // Recurse if necessary for the next device
+  if (len > (dev->end + 1 - flash_base)) {
+    return cyg_flash_lock(dev->end+1, 
+                          len - (dev->end + 1 - flash_base),
+                          err_address);
+  }
+
+  return CYG_FLASH_ERR_OK;
+}
+
+__externC int 
+cyg_flash_unlock(const cyg_flashaddr_t flash_base, 
+                 size_t len, 
+                 cyg_flashaddr_t *err_address)
+{
+  cyg_flashaddr_t block, end_addr;
+  struct cyg_flash_dev * dev;
+  size_t unlock_count;
+  int stat = CYG_FLASH_ERR_OK;
+  HAL_FLASH_CACHES_STATE(d_cache, i_cache);
+
+  dev = find_dev(flash_base, &stat);
+  if (!dev) return stat;
+  if (!dev->funs->flash_block_unlock) return CYG_FLASH_ERR_INVALID;
+
+  CHECK_SOFT_WRITE_PROTECT(flash_base, len);
+  
+  LOCK(dev);
+  if (len > (dev->end + 1 - flash_base)) {
+      end_addr = dev->end;
+  } else {
+      end_addr = flash_base + len - 1;
+  }
+  block         = flash_block_begin(flash_base, dev);
+  unlock_count  = (end_addr + 1) - block;
+  
+  CHATTER(dev, "... Unlocking from %p-%p: ", (void*)block, (void*)end_addr);
+  
+  HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+  FLASH_Enable(flash_base, end_addr);
+  while (unlock_count > 0) {
+    size_t    block_size  = flash_block_size(dev, block);
+    if (unlock_count < block_size) {
+        unlock_count = block_size;
+    }
+    stat = dev->funs->flash_block_unlock(dev,block);
+    
+    if (CYG_FLASH_ERR_OK != stat && err_address) {
+      *err_address = block;
+      break;
+    }
+    block           += block_size;
+    unlock_count    -= block_size;
+    
+    CHATTER(dev, ".");
+  }
+  FLASH_Disable(flash_base, end_addr);
+  HAL_FLASH_CACHES_ON(d_cache, i_cache);
+  CHATTER(dev, "\n");
+  UNLOCK(dev);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return stat;
+  }
+  
+  // Recurse if necessary for the next device
+  if (len > (dev->end + 1 - flash_base)) {
+    return cyg_flash_lock(dev->end+1, 
+                          len - (dev->end + 1 - flash_base),
+                          err_address);
+  }
+  return CYG_FLASH_ERR_OK;
 }
 #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";
     }
 }
 
+// Dummy routines to put into the device function tables, to handle
+// unsupported/unnecessary functionality. For example not all devices
+// support block locking.
+//
+// A dummy initialization routine, for platforms where everything is
+// done statically and there is no need to check device ids or
+// anything similar.
+int
+cyg_flash_devfn_init_nop(struct cyg_flash_dev* dev)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    return CYG_FLASH_ERR_OK;
+}
+
+// A dummy query routine. The implementation of this is specific to
+// each device driver, so some device drivers may choose to do
+// nothing.
+size_t
+cyg_flash_devfn_query_nop(struct cyg_flash_dev* dev, void* data, size_t len)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    CYG_UNUSED_PARAM(void*, data);
+    CYG_UNUSED_PARAM(size_t, len);
+    return 0;
+}
+
+// Dummy lock/unlock routines
+int
+cyg_flash_devfn_lock_nop(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    CYG_UNUSED_PARAM(cyg_flashaddr_t, addr);
+#if defined(CYGHWR_IO_FLASH_BLOCK_LOCKING) && (1 < CYGHWR_IO_FLASH_DEVICE)
+// If we've been built with locking, and there's more than one flash
+// device in the system, then this is probably only being called because
+// we can't tell what devices do and don't support locking, and for a _nop
+// function this is the device that doesn't support locking. So we don't
+// complain if we're asked to.
+    return CYG_FLASH_ERR_OK;
+#else
+    return CYG_FLASH_ERR_DRV_WRONG_PART;
+#endif
+}
+
+int
+cyg_flash_devfn_unlock_nop(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr)
+{
+    CYG_UNUSED_PARAM(struct cyg_flash_dev*, dev);
+    CYG_UNUSED_PARAM(cyg_flashaddr_t, addr);
+#if defined(CYGHWR_IO_FLASH_BLOCK_LOCKING) && (1 < CYGHWR_IO_FLASH_DEVICE)
+// If we've been built with locking, and there's more than one flash
+// device in the system, then this is probably only being called because
+// we can't tell what devices do and don't support locking, and for a _nop
+// function this is the device that doesn't support locking. So we don't
+// complain if we're asked to.
+    return CYG_FLASH_ERR_OK;
+#else
+    return CYG_FLASH_ERR_DRV_WRONG_PART;
+#endif
+}
+
+// On some architectures there are problems calling the .2ram
+// functions from the main ones. Specifically the compiler may issue a
+// short call, even though the flash and ram are too far apart. The
+// solution is to indirect via a function pointer, but the simplistic
+// approach is vulnerable to compiler optimization. Hence the function
+// pointer is passed through an anonymizer.
+void*
+cyg_flash_anonymizer(void* fn)
+{
+    return fn;
+}
+
 // EOF io/flash/..../flash.c
Index: packages/io/flash/current/src/flash_legacy.h
===================================================================
RCS file: packages/io/flash/current/src/flash_legacy.h
diff -N packages/io/flash/current/src/flash_legacy.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ packages/io/flash/current/src/flash_legacy.h	18 Nov 2008 00:54:13 -0000
@@ -0,0 +1,186 @@
+//==========================================================================
+//
+//      flash_legacy.h
+//
+//      Flash programming - some internal implementation details.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2003 Gary Thomas
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 eCosCentric Limited
+//
+// 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####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/io_flash.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+
+
+// 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(__start, __end) CYGIMP_FLASH_ENABLE((void *)__start, (void *)__end)
+extern void CYGIMP_FLASH_ENABLE(void *, void *);
+#else
+# define FLASH_Enable(_start_, _end_) CYG_EMPTY_STATEMENT
+#endif
+#ifdef  CYGIMP_FLASH_DISABLE
+# define FLASH_Disable(__start, __end) CYGIMP_FLASH_DISABLE((void *)__start, (void *)__end)
+extern void CYGIMP_FLASH_DISABLE(void *, void *);
+#else
+# define FLASH_Disable(_start_, _end_) CYG_EMPTY_STATEMENT
+#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
+
+//---------------------------------------------------------------------------
+// If all of the flash devices handle cache themselves, or do not need any
+// special cache treatment, then the flash macros can be no-ops.
+#ifndef CYGHWR_IO_FLASH_DEVICE_NEEDS_CACHE_HANDLED
+# undef HAL_FLASH_CACHES_OFF
+# undef HAL_FLASH_CACHES_ON
+# undef HAL_FLASH_CACHES_STATE
+# define HAL_FLASH_CACHES_OFF(_d_, _i_)     CYG_EMPTY_STATEMENT
+# define HAL_FLASH_CACHES_ON(_d_, _i_)      CYG_EMPTY_STATEMENT
+# define HAL_FLASH_CACHES_STATE(_d_, _i_)   CYG_EMPTY_STATEMENT
+#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
+
+#ifndef HAL_FLASH_CACHES_STATE
+# define HAL_FLASH_CACHES_STATE(_d_, _i_) int _d_, _i_
+#endif
Index: packages/io/flash/current/src/flashiodev.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/src/flashiodev.c,v
retrieving revision 1.8
diff -u -5 -p -r1.8 flashiodev.c
--- packages/io/flash/current/src/flashiodev.c	29 Apr 2004 06:37:56 -0000	1.8
+++ packages/io/flash/current/src/flashiodev.c	18 Nov 2008 00:54:13 -0000
@@ -7,10 +7,12 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2004, 2007 eCosCentric Ltd.
 //
 // 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.
 //
@@ -30,267 +32,520 @@
 // 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):    jlarmour
-// Contributors: woehler
-// Date:         2002-01-16
+// Contributors: woehler, Andrew Lunn
+// Date:         2004-12-03
 // Purpose:      
 // Description:  
 //              
 //####DESCRIPTIONEND####
 //
 //==========================================================================
 
-#define _FLASH_PRIVATE_
-#include <pkgconf/io_flash.h>
+// INCLUDES
 
+#include <pkgconf/io_flash.h>
 #include <errno.h>
 #include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
 #include <cyg/io/devtab.h>
 #include <cyg/io/config_keys.h>
 #include <cyg/io/flash.h>
 #include <string.h> // memcpy
 #include <cyg/hal/hal_if.h>
+#include <cyg/hal/drv_api.h> // mutexes
+
+// MACROS
 
 #define MIN(x,y) ((x)<(y) ? (x) : (y))
+#define MAX(x,y) ((x)>(y) ? (x) : (y))
+
+// TYPES
 
 struct flashiodev_priv_t{
-	char *start;
-	char *end;
+  cyg_devtab_entry_t handle;
+  cyg_flashaddr_t start;
+  cyg_flashaddr_t end;
+  cyg_bool        valid;
 };
+// FUNCTION PROTOTYPES
 
-static struct flashiodev_priv_t flashiodev_priv[1];
+static bool flashiodev_init( struct cyg_devtab_entry *tab );
+static Cyg_ErrNo
+flashiodev_lookup(struct cyg_devtab_entry **tab,
+                  struct cyg_devtab_entry  *sub_tab,
+                  const char *name) ;
+static Cyg_ErrNo
+flashiodev_bread( cyg_io_handle_t handle, void *buf, cyg_uint32 *len,
+                  cyg_uint32 pos);
+static Cyg_ErrNo
+flashiodev_bwrite( cyg_io_handle_t handle, const void *buf, cyg_uint32 *len,
+                   cyg_uint32 pos );
+static Cyg_ErrNo
+flashiodev_get_config( cyg_io_handle_t handle,
+                       cyg_uint32 key,
+                       void* buf,
+                       cyg_uint32* len);
+static Cyg_ErrNo
+flashiodev_set_config( cyg_io_handle_t handle,
+                       cyg_uint32 key,
+                       const void* buf,
+                       cyg_uint32* len);
+
+// STATICS/GLOBALS
+
+static struct flashiodev_priv_t flashiodev_table[CYGNUM_IO_FLASH_BLOCK_DEVICES];
+static cyg_drv_mutex_t flashiodev_table_lock;
+
+BLOCK_DEVIO_TABLE( cyg_io_flashdev_ops,
+                   &flashiodev_bwrite,
+                   &flashiodev_bread,
+                   NULL, // no select
+                   &flashiodev_get_config,
+                   &flashiodev_set_config
+                   ); 
+
+
+BLOCK_DEVTAB_ENTRY( cyg_io_flashdev,
+                    "/dev/flash/",
+                    NULL,
+                    &cyg_io_flashdev_ops,
+                    &flashiodev_init,
+                    &flashiodev_lookup,
+                    NULL );
+
+// FUNCTIONS
 
 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;
+  int stat = cyg_flash_init( &dummy_printf );
+  cyg_ucount32 i;
+
+  if (stat == CYG_FLASH_ERR_OK)
+  {
+      for (i=0; i<CYGNUM_IO_FLASH_BLOCK_DEVICES; i++)
+      {
+          CYG_ASSERT( tab->handlers == &cyg_io_flashdev_ops, "Unexpected handlers - not flashdev_ops" );
+          flashiodev_table[i].handle.handlers = &cyg_io_flashdev_ops;
+          flashiodev_table[i].handle.status = CYG_DEVTAB_STATUS_BLOCK;
+          flashiodev_table[i].handle.priv = &flashiodev_table[i]; // link back
+      } // for
+      cyg_drv_mutex_init( &flashiodev_table_lock );
+  } // if
+
+  return (stat == CYG_FLASH_ERR_OK);
+} // flashiodev_init()
+
+#ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
+static cyg_uint32
+parsenum( const char **str )
+{
+    cyg_uint32 num = 0;
+    cyg_uint8 base = 10;
 
+    // trim leading 0s
+    while (**str == '0')
+        (*str)++;
+    // crudely detect hex by assuming that something with a leading 0x
+    // can just match the 'x' with a leading 0 being trimmed.
+    if ( (**str == 'x') || (**str == 'X') )
+    {
+        (*str)++;
+        base = 16;
+    }
+
+    while (**str) {
+        switch (**str)
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            num = (num * base) + (**str-'0');
+            break;
+        case 'a':
+        case 'b':
+        case 'c':
+        case 'd':
+        case 'e':
+        case 'f':
+            if ( base != 16 )
+                return num;
+            num = (num * base) + (**str-'a' + 10);
+            break;
+        case 'A':
+        case 'B':
+        case 'C':
+        case 'D':
+        case 'E':
+        case 'F':
+            if ( base != 16 )
+                return num;
+            num = (num << 4) + (**str-'A' + 10);
+            break;
+        default:
+            return num;
+        } // switch
+        (*str)++;
+    } // while
+
+    return num;
+} // parsenum()
+#endif // ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
+
+static Cyg_ErrNo
+flashiodev_lookup(struct cyg_devtab_entry **tab,
+                  struct cyg_devtab_entry  *sub_tab,
+                  const char *name) 
+{
+    // We enter with **tab being the entry for /dev/flash only
+    // We will leave with **tab instead pointing to a newly configured flash device instance
+    // We could allocate the space for recording these dynamically, but that's overkill,
+    // so we instead choose the eCos ethos of "let the user decide at configure time".
+    // After all there's a good chance there'll be only one or two needed at one time.
+    
+    // There are two styles of path:
+    //    /dev/flash/fis/<fispartitionname>
+    // and
+    //    /dev/flash/<deviceno>/<offset>[,<length>]
+
+    cyg_flashaddr_t start=0;
+    cyg_flashaddr_t end=0;
+    cyg_bool valid = false;
+
+#ifdef CYGFUN_IO_FLASH_BLOCK_FROM_FIS
+    // First, support FIS
+    if ((name[0] == 'f') && (name[1] == 'i') &&
+        (name[2] == 's') && (name[3] == '/'))
+    {
+        CYG_ADDRESS	flash_base;
+        unsigned long	size;
+    
         if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, 
-                                        CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1,
+                                        (char *)&name[4],
                                         &flash_base))
-            return false;
+            return -ENOENT; 
+    
         if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, 
-                                        CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1,
+                                        (char *)&name[4],
                                         &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;
+            return -ENODEV; // If the previous call worked, then this failing would be very wrong.
+        start = flash_base;
+        end = flash_base + size - 1;
+        valid = true;
     } else
-        return false;
-} // flashiodev_init()
+#endif // ifdef CYGFUN_IO_FLASH_BLOCK_FROM_FIS
+#ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
+    // Next, support device numbers with offsets encoded in path name
+    // Note that for now we assume < 10 flash devices. I think this is reasonable
+    // to avoid unnecessary code. It can be changed later if needed.
+    if ( (name[0] >= '0') && (name[0] <= '9') )
+    {
+        cyg_uint32 flashdevno = name[0] - '0';
+        int res;
+        cyg_flash_info_t info;
+        cyg_uint32 offset;
+        const char *tempstr;
+
+        if (name[1] != '/')
+            return -ENOTSUP;
+        res = cyg_flash_get_info( flashdevno, &info );
+        if (CYG_FLASH_ERR_OK != res)
+            return -ENOENT;
+
+        // Now modify with offset and optional length
+        tempstr = &name[2];
+        offset = parsenum( &tempstr );
 
-#if 0
-static Cyg_ErrNo
-flashiodev_lookup( struct cyg_devtab_entry **tab, 
-                   struct cyg_devtab_entry *sub_tab,
-                   const char *name)
-{   
-} // flashiodev_lookup()
+        start = info.start + offset;
+        end = info.end;
+        
+        if (*tempstr == ',') // optional length
+        {
+            cyg_uint32 length;
+
+            tempstr++;
+            length = parsenum( &tempstr );
+
+            // Check we don't exceed end of device.
+            // Note the flash end address is the last byte of addressible flash *not* the base+size
+            if ( (start + length - 1) > end )
+                return -EINVAL;
+            end = start + length - 1;
+        }
+        valid = true;
+    } // else if
 #endif
 
+    if (valid)
+    {
+        // Find a slot and use it
+        cyg_ucount32 i;
+
+        cyg_drv_mutex_lock( &flashiodev_table_lock );
+        for (i=0; i<CYGNUM_IO_FLASH_BLOCK_DEVICES; i++)
+        {
+            if ( !flashiodev_table[i].valid ) {
+                flashiodev_table[i].start = start;
+                flashiodev_table[i].end = end;
+                flashiodev_table[i].valid = true;
+                cyg_drv_mutex_unlock( &flashiodev_table_lock );
+
+                *tab = &flashiodev_table[i].handle;
+                // Theoretically we could set up the devtab entry more fully, e.g.
+                // the name, but I don't see the need!
+                return ENOERR;
+            } // if
+        } // for
+        cyg_drv_mutex_unlock( &flashiodev_table_lock );
+
+        // If we got here we must have reached the end of the table without finding a space
+        return -ENOMEM;
+    }
+    // Wasn't valid, so....
+    return -ENOENT;
+} // flashiodev_lookup()
+
 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 = ENOERR;
+  int flasherr;
+  
+  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
+  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
+  
 #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;
+  
+  flasherr = cyg_flash_read( startpos,(void *)buf, *len, NULL );
+  
+  if ( flasherr != 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;
-
-#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;
-#endif
-    err = flash_program( startpos, 
-                         (void *)buf, *len, &erraddr );
-
-    if ( err )
-        err = -EIO; // just something sane
-    return err;
+{
+  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;
+  int flasherr;
+  cyg_flashaddr_t startpos = dev->start + pos;
+  
+  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
+  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
+  
+  // Unlike some other cases we _do_ do bounds checking on this all the time, because
+  // the consequences of writing over the wrong bit of flash are so nasty.
+  cyg_flashaddr_t endpos = startpos + *len - 1;
+  if ( startpos < dev->start )
+    return -EINVAL;
+  if ( endpos > dev->end )
+    return -EINVAL;
+
+  flasherr = cyg_flash_program( startpos, (void *)buf, *len, NULL );
+  
+  if ( flasherr != CYG_FLASH_ERR_OK )
+    err = -EIO; // just something sane
+  return err;
 } // flashiodev_bwrite()
 
 static Cyg_ErrNo
 flashiodev_get_config( cyg_io_handle_t handle,
                        cyg_uint32 key,
                        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;
+  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:
+  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
+  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
+  
+  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;
-
 #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;
+      if (*len != sizeof( cyg_io_flash_getconfig_erase_t ) )
+        return -EINVAL;
 #endif
-            e->flasherr = flash_erase( startpos, e->len, e->err_address );
-        }
-        return ENOERR;
+      {
+        cyg_io_flash_getconfig_erase_t *e = (cyg_io_flash_getconfig_erase_t *)buf;
+        cyg_flashaddr_t startpos = dev->start + e->offset;
+        
+        // Unlike some other cases we _do_ do bounds checking on this all the time, because
+        // the consequences of erasing the wrong bit of flash are so nasty.
+        cyg_flashaddr_t endpos = startpos + e->len - 1;
+        if ( startpos < dev->start )
+          return -EINVAL;
+        if ( endpos > dev->end )
+          return -EINVAL;
+
+        e->flasherr = cyg_flash_erase( startpos, e->len, &e->err_address );
+      }
+      return ENOERR;
     }
-    case CYG_IO_GET_CONFIG_FLASH_DEVSIZE:
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING    
+  case CYG_IO_GET_CONFIG_FLASH_LOCK:
     {
-        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;
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+      if (*len != sizeof( cyg_io_flash_getconfig_lock_t ) )
+        return -EINVAL;
+#endif
+      {
+        cyg_io_flash_getconfig_lock_t *d = (cyg_io_flash_getconfig_lock_t *)buf;
+        cyg_flashaddr_t startpos = dev->start + d->offset;
 
-	    //d->dev_size = flash_info.blocks * flash_info.block_size;
-			d->dev_size = dev->end - dev->start;
-        }
-        return ENOERR;
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time        
+        cyg_flashaddr_t endpos = startpos + d->len - 1;
+        if ( startpos < dev->start )
+          return -EINVAL;
+        if ( endpos > dev->end )
+          return -EINVAL;
+#endif
+        
+        d->flasherr = cyg_flash_lock( startpos, d->len, &d->err_address );
+      }
+      return ENOERR;
     }
 
-    case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE:
+  case CYG_IO_GET_CONFIG_FLASH_UNLOCK:
     {
-        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 (*len != sizeof( cyg_io_flash_getconfig_unlock_t ) )
+        return -EINVAL;
+#endif
+      {
+        cyg_io_flash_getconfig_unlock_t *d = (cyg_io_flash_getconfig_unlock_t *)buf;
+        cyg_flashaddr_t startpos = dev->start + d->offset;
 
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time        
+        cyg_flashaddr_t endpos = startpos + d->len - 1;
         if ( startpos < dev->start )
-            return -EINVAL;
-        if ( startpos > flashend )
-            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;
+          return -EINVAL;
+        if ( endpos > dev->end )
+          return -EINVAL;
+#endif        
+        d->flasherr = cyg_flash_unlock( startpos, d->len, &d->err_address );
+      }
+      return ENOERR;
+    }
+#endif
+    
+  case CYG_IO_GET_CONFIG_FLASH_DEVSIZE:
+    {
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+      if ( *len != sizeof( cyg_io_flash_getconfig_devsize_t ) )
+        return -EINVAL;
+#endif
+      {
+        cyg_io_flash_getconfig_devsize_t *d =
+          (cyg_io_flash_getconfig_devsize_t *)buf;
+
+        d->dev_size = dev->end - dev->start + 1;
+      }
+      return ENOERR;
     }
 
-    default:
+  case CYG_IO_GET_CONFIG_FLASH_DEVADDR:
+    {
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+      if ( *len != sizeof( cyg_io_flash_getconfig_devaddr_t ) )
         return -EINVAL;
+#endif
+      {
+        cyg_io_flash_getconfig_devaddr_t *d =
+          (cyg_io_flash_getconfig_devaddr_t *)buf;
+
+        d->dev_addr = dev->start;
+      }
+      return ENOERR;
     }
+
+  case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE:
+    {
+      cyg_io_flash_getconfig_blocksize_t *b =
+        (cyg_io_flash_getconfig_blocksize_t *)buf;
+      cyg_flashaddr_t pos = dev->start + b->offset;
+      
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+      if ( pos < dev->start )
+        return -EINVAL;
+      if ( pos > dev->end )
+        return -EINVAL;
+      if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) )
+        return -EINVAL;
+#endif  
+
+      b->block_size = cyg_flash_block_size( pos );
+      return ENOERR;
+    }
+    
+  default:
+    return -EINVAL;
+  }
 } // flashiodev_get_config()
 
 static Cyg_ErrNo
 flashiodev_set_config( cyg_io_handle_t handle,
                        cyg_uint32 key,
                        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:
-    {
-        CYG_ADDRESS     flash_base;
-	unsigned long   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;
-    }
-#endif
-    default:
-        return -EINVAL;
+  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
+  
+  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
+  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
+  
+  switch (key) {
+  case CYG_IO_SET_CONFIG_CLOSE:
+    {
+        Cyg_ErrNo err = ENOERR;
+        cyg_drv_mutex_lock( &flashiodev_table_lock );
+        if (!dev->valid)
+        {
+            err = -EBADF;
+        } else {
+            dev->valid = false;
+        }
+        cyg_drv_mutex_unlock( &flashiodev_table_lock );
+        return err;
     }
+  default:
+    return -EINVAL;
+  }
 } // flashiodev_set_config()
 
-// get_config/set_config should be added later to provide the other flash
-// operations possible, like erase etc.
-
-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,
-                    0,
-                    &cyg_io_flashdev1_ops,
-                    &flashiodev_init,
-                    0, // No lookup required
-                    &flashiodev_priv[0] );
-
 // EOF flashiodev.c
Index: packages/io/flash/current/src/flashiodevlegacy.c
===================================================================
RCS file: packages/io/flash/current/src/flashiodevlegacy.c
diff -N packages/io/flash/current/src/flashiodevlegacy.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ packages/io/flash/current/src/flashiodevlegacy.c	18 Nov 2008 00:54:13 -0000
@@ -0,0 +1,415 @@
+//==========================================================================
+//
+//      flashiodev.c
+//
+//      Old flash device interface to I/O subsystem
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 Andrew Lunn
+//
+// 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.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    jlarmour
+// Contributors: woehler, Andrew Lunn
+// Date:         2002-01-16
+// Purpose:      
+// Description:  
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#define _FLASH_PRIVATE_
+#include <pkgconf/io_flash.h>
+
+#include <errno.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/io/devtab.h>
+#include <cyg/io/config_keys.h>
+#include <cyg/io/flash.h>
+#include <string.h> // memcpy
+#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{
+  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;
+  cyg_bool        init;
+};
+
+static int dummy_printf( const char *fmt, ... ) {return 0;}
+
+static bool
+flashiodev_init( struct cyg_devtab_entry *tab )
+{
+  int stat = cyg_flash_init( &dummy_printf );
+
+  return (stat == CYG_FLASH_ERR_OK);
+} // flashiodev_init()
+
+static Cyg_ErrNo
+flashiodev_lookup(struct cyg_devtab_entry **tab,
+                  struct cyg_devtab_entry  *sub_tab,
+                  const char *name) 
+{
+  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)(*tab)->priv;
+  cyg_flash_info_t info;
+  cyg_uint32 i;
+  int stat;
+
+  if (dev->init)
+    return ENOERR;
+
+  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 ENOERR; 
+ // Strange, yes, but needed since we have to do a lookup in order to
+ // set the name using cyg_io_config_set. If we fail here you cannot
+ // do a set. Since dev->init will still be false and attempts to
+ // actually use the device will fail, so it is safe.
+    
+    if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, 
+                                    dev->fis_name,
+                                    &size))
+      return ENOERR; // Ditto.
+    dev->start = flash_base;
+    dev->end = flash_base + size;
+  }
+  if (dev->use_offset) {
+    // dev->start contains the offset to the beginning of the block
+    // dev->end is the length of the block
+    cyg_flash_info_t info;
+    
+    cyg_flash_get_info(0, &info);
+    dev->start = dev->start + info.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;
+  }
+  
+  stat = cyg_flash_get_info_addr(dev->start, &info);
+  if (stat != CYG_FLASH_ERR_OK) {
+    return ENODEV;
+    }
+  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);
+  }
+
+  dev->init = 1;
+  return ENOERR;
+} // flashiodev_lookup()
+
+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;
+
+  cyg_flashaddr_t startpos = dev->start + pos;
+  Cyg_ErrNo err;
+  
+  if (!dev->init) {
+    return -EINVAL;
+  }
+  
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+  cyg_flashaddr_t endpos = startpos + *len - 1;
+  if ( startpos < dev->start )
+    return -EINVAL;
+  if ( endpos > dev->end )
+    return -EINVAL;
+#endif
+  
+  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;
+  cyg_flashaddr_t startpos = dev->start + pos;
+  
+  if (!dev->init) {
+    return -EINVAL;
+  }
+  
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+  cyg_flashaddr_t endpos = startpos + *len - 1;
+  if ( startpos < dev->start )
+    return -EINVAL;
+  if ( endpos > dev->end )
+    return -EINVAL;
+#endif
+  err = cyg_flash_program( startpos, (void *)buf, *len, NULL );
+  
+  if ( err )
+    err = -EIO; // just something sane
+  return err;
+} // flashiodev_bwrite()
+
+static Cyg_ErrNo
+flashiodev_get_config( cyg_io_handle_t handle,
+                       cyg_uint32 key,
+                       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;
+
+  if (!dev->init) {
+    return -EINVAL;
+  }
+  
+  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;
+        cyg_flashaddr_t startpos = dev->start + e->offset;
+        
+#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
+        cyg_flashaddr_t endpos = startpos + e->len - 1;
+        if ( startpos < dev->start )
+          return -EINVAL;
+        if ( endpos > dev->end )
+          return -EINVAL;
+#endif
+        e->flasherr = cyg_flash_erase( startpos, e->len, e->err_address );
+      }
+      return ENOERR;
+    }
+  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 = dev->end - dev->start;
+      }
+      return ENOERR;
+    }
+    
+  case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE:
+    {
+      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
+      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 = dev->block_size;
+      return ENOERR;
+    }
+    
+  default:
+    return -EINVAL;
+  }
+} // flashiodev_get_config()
+
+static Cyg_ErrNo
+flashiodev_set_config( cyg_io_handle_t handle,
+                       cyg_uint32 key,
+                       const 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_SET_CONFIG_FLASH_FIS_NAME:
+    {
+      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;
+
+      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);
+      }
+      dev->init = 1;
+     
+      return ENOERR;
+    }
+  default:
+    return -EINVAL;
+  }
+} // flashiodev_set_config()
+
+// get_config/set_config should be added later to provide the other flash
+// operations possible, like erase etc.
+
+#define CYG_FLASHIODEV_DEV(start, end, fis, static, offset, name) \
+   { start, end, fis, static, offset, name, 0, 0 }
+
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1
+static struct flashiodev_priv_t priv1 = CYG_FLASHIODEV_DEV(
+  0,       // start
+  0,       // end
+  1,       // use_fis
+  0,       // use_static
+  0,       // use_offset
+  CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1);
+#endif
+
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_1 
+static struct flashiodev_priv_t priv1 = CYG_FLASHIODEV_DEV(
+  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
+#endif
+
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_1
+static struct flashiodev_priv_t priv1 = CYG_FLASHIODEV_DEV(
+  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
+#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,
+                    0,
+                    &cyg_io_flashdev1_ops,
+                    &flashiodev_init,
+                    &flashiodev_lookup,
+                    &priv1 );
+
+#ifdef CYGSEM_IO_FLASH_BLOCK_DEVICE_2 
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_2
+static struct flashiodev_priv_t priv2 = CYG_FLASHIODEV_DEV(
+  0,       // start
+  0,       // end
+  1,       // use_fis
+  0,       // use_static
+  0,       // use_offset
+  CYGDAT_IO_FLASH_BLOCK_FIS_NAME_2);
+#endif
+
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_2 
+static struct flashiodev_priv_t priv2 = CYG_FLASHIODEV_DEV(
+  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
+#endif
+
+#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_2
+static struct flashiodev_priv_t priv2 = CYG_FLASHIODEV_DEV(
+  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
+#endif
+
+BLOCK_DEVTAB_ENTRY( cyg_io_flashdev2,
+                    CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_2,
+                    0,
+                    &cyg_io_flashdev1_ops,
+                    &flashiodev_init,
+                    &flashiodev_lookup,
+                    &priv2 );
+#endif
+
+// EOF flashiodev.c
Index: packages/io/flash/current/src/legacy_api.c
===================================================================
RCS file: packages/io/flash/current/src/legacy_api.c
diff -N packages/io/flash/current/src/legacy_api.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ packages/io/flash/current/src/legacy_api.c	18 Nov 2008 00:54:13 -0000
@@ -0,0 +1,162 @@
+//==========================================================================
+//
+//      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>
+
+#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)
+{
+  int err;
+  cyg_flash_info_t info;
+  
+  err = cyg_flash_get_info(0, &info);
+  if (err != CYG_FLASH_ERR_OK) {
+    return err;
+  }
+
+  *start = (void *)info.start;
+  *end = (void *)info.end;
+
+  return CYG_FLASH_ERR_OK;
+}
+
+
+int
+flash_get_block_info(int *block_size, int *blocks)
+{
+  size_t biggest_size=0;
+  cyg_uint32 i;
+  cyg_flash_info_t info;
+  int err;
+  
+  err = cyg_flash_get_info(0, &info);
+  if (err != CYG_FLASH_ERR_OK) {
+    return err;
+  }
+
+  // Find the biggest size of blocks
+  for (i=0; i < info.num_block_infos; i++) {
+    if (info.block_info[i].block_size > biggest_size) {
+      biggest_size = info.block_info[i].block_size;
+    }
+  }
+  
+  // Calculate the number of biggest size blocks
+  *block_size = biggest_size;
+  *blocks = 0;
+  for (i=0; i < info.num_block_infos; i++) {
+    *blocks += (info.block_info[i].block_size *
+                info.block_info[i].blocks) /
+      biggest_size;
+  }
+  return CYG_FLASH_ERR_OK;
+}
+
+int
+flash_erase(void *addr, int len, void **err_addr)
+{
+  return cyg_flash_erase((cyg_flashaddr_t)addr, len, 
+                         (cyg_flashaddr_t *)err_addr);
+}
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+
+int
+flash_lock(void *addr, int len, void **err_addr)
+{
+  return cyg_flash_lock((cyg_flashaddr_t)addr, len, 
+                        (cyg_flashaddr_t *)err_addr);
+}
+
+int
+flash_unlock(void *addr, int len, void **err_addr)
+{
+  return cyg_flash_unlock((cyg_flashaddr_t)addr, len, 
+                          (cyg_flashaddr_t *)err_addr);
+}
+
+#endif
+
+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);
+}
+
+char *flash_errmsg(int err)
+{
+  return (char *)cyg_flash_errmsg(err);
+}
+
+// EOF legacy_api.c
Index: packages/io/flash/current/src/legacy_dev.c
===================================================================
RCS file: packages/io/flash/current/src/legacy_dev.c
diff -N packages/io/flash/current/src/legacy_dev.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ packages/io/flash/current/src/legacy_dev.c	18 Nov 2008 00:54:13 -0000
@@ -0,0 +1,240 @@
+//==========================================================================
+//
+//      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
+// Copyright (C) 2004, 2006 eCosCentric Limited
+//
+// 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>
+
+#include <cyg/io/flash.h>
+#include <cyg/io/flash_dev.h>
+#include "flash_legacy.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_flash_block_info_t block_info[1];
+
+  flash_info.pf = dev->pf;
+  
+  err=flash_hwr_init();
+
+  if (!err) {
+    dev->start = (cyg_flashaddr_t)flash_info.start;
+    dev->end = dev->start + flash_info.block_size * flash_info.blocks - 1; 
+    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;
+}
+
+static size_t 
+legacy_flash_query (struct cyg_flash_dev *dev, 
+                    void * data, 
+                    size_t len)
+{
+  typedef void code_fun(void*);
+  code_fun *_flash_query;
+  
+  _flash_query = (code_fun*) cyg_flash_anonymizer(&flash_query);
+  
+  (*_flash_query)(data);
+  
+  return len;
+}
+
+static int 
+legacy_flash_erase_block (struct cyg_flash_dev *dev, 
+                          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;
+  int    stat;
+  
+  _flash_erase_block = (code_fun*) cyg_flash_anonymizer(&flash_erase_block);
+
+  stat =  (*_flash_erase_block)(block_base, block_size);
+  return flash_hwr_map_error(stat);
+}
+
+static int
+legacy_flash_program(struct cyg_flash_dev *dev, 
+                     cyg_flashaddr_t base, 
+                     const void* data, 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_size -1);
+  int    stat;
+  
+  _flash_program_buf = (code_fun*) cyg_flash_anonymizer(&flash_program_buf);
+
+  stat = (*_flash_program_buf)(base, data, len, block_mask, flash_info.buffer_size);
+  return flash_hwr_map_error(stat);
+}
+
+#ifdef CYGSEM_IO_FLASH_READ_INDIRECT
+static int 
+legacy_flash_read (struct cyg_flash_dev *dev, 
+                   const cyg_flashaddr_t base, 
+                   void* data, size_t len)
+{
+  typedef int code_fun(const cyg_flashaddr_t, 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_size -1);
+  int    stat;
+  _flash_read_buf = (code_fun*) cyg_flash_anonymizer(&flash_read_buf);
+  
+  stat = (*_flash_read_buf)(base, data, len, block_mask, block_size);
+  return flash_hwr_map_error(stat);
+}
+
+# define LEGACY_FLASH_READ  legacy_flash_read
+#else
+# define LEGACY_FLASH_READ  ((int (*)(struct cyg_flash_dev*, const cyg_flashaddr_t, void*, const size_t))0)
+#endif
+
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+static int 
+legacy_flash_block_lock (struct cyg_flash_dev *dev, 
+                         const cyg_flashaddr_t block_base)
+{
+  typedef int code_fun(cyg_flashaddr_t);
+  code_fun *_flash_lock_block;
+  int       stat;  
+  _flash_lock_block = (code_fun*) cyg_flash_anonymizer(&flash_lock_block);
+
+  stat = (*_flash_lock_block)(block_base);
+  return flash_hwr_map_error(stat);
+}
+
+static int 
+legacy_flash_block_unlock (struct cyg_flash_dev *dev, 
+                           const cyg_flashaddr_t block_base)
+{
+  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;
+  int        stat;  
+  _flash_unlock_block = (code_fun*) cyg_flash_anonymizer(&flash_unlock_block);
+  
+  stat = (*_flash_unlock_block)(block_base, block_size, blocks);
+  return flash_hwr_map_error(stat);
+}
+#endif
+
+void
+flash_dev_query(void* data)
+{
+    typedef void code_fun(void*);
+    code_fun *_flash_query;
+    HAL_FLASH_CACHES_STATE(d_cache, i_cache);
+
+    _flash_query = (code_fun*) cyg_flash_anonymizer(&flash_query);
+
+    HAL_FLASH_CACHES_OFF(d_cache, i_cache);
+    (*_flash_query)(data);
+    HAL_FLASH_CACHES_ON(d_cache, i_cache);
+}
+
+static const CYG_FLASH_FUNS(cyg_legacy_funs, 
+                            legacy_flash_init,
+                            legacy_flash_query,
+                            legacy_flash_erase_block,
+                            legacy_flash_program,
+                            LEGACY_FLASH_READ,
+                            legacy_flash_block_lock,
+                            legacy_flash_block_unlock
+    );
+
+CYG_FLASH_DRIVER(cyg_zzlegacy_flashdev,
+                 &cyg_legacy_funs,
+                 0,     // Flags
+                 0,     // Start address, filled in by init
+                 0,     // End address, filled in by init
+                 0,     // Number of block infos, filled in by init
+                 NULL,  // Block infos, again filled in by init
+                 NULL   // Driver private data, none needed
+    );
Index: packages/io/flash/current/tests/flash1.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/tests/flash1.c,v
retrieving revision 1.3
diff -u -5 -p -r1.3 flash1.c
--- packages/io/flash/current/tests/flash1.c	3 Aug 2005 21:04:28 -0000	1.3
+++ packages/io/flash/current/tests/flash1.c	18 Nov 2008 00:54:13 -0000
@@ -8,10 +8,11 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2004 Gary Thomas
+// Copyright (C) 2004, 2005 eCosCentric Limited
 //
 // 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.
 //
@@ -59,10 +60,18 @@
 #include <cyg/infra/testcase.h>
 
 #include <cyg/io/flash.h>
 #include <cyg/hal/hal_if.h>
 
+#ifndef CYGSEM_IO_FLASH_LEGACY_API
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_NA("Only usable with legacy API");
+}
+#else
 externC void
 cyg_start( void )
 {
     int stat;
     void *err_addr;
@@ -74,10 +83,12 @@ cyg_start( void )
     CYG_ADDRWORD test_buf1, test_buf2;
     cyg_uint32 *lp1, *lp2;
     int i, len;
     cyg_bool passed, ok;
 
+    CYG_TEST_INIT();
+
 #if 0
     int j;
     
     diag_printf("Testing udelay: ");
     for (i = 0;  i < 30;  i++) {
@@ -122,20 +133,31 @@ cyg_start( void )
         CYG_TEST_FAIL_FINISH("FLASH not enough heap space - reduce size of test region");
     }
     diag_printf("... Using test buffers at %p and %p\n", (void *)test_buf1, (void *)test_buf2);
     flash_test_start = (void *)(flash_start + CYGNUM_IO_FLASH_TEST_OFFSET);
 
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING    
+    // Unlock test
+    diag_printf("... Unlock test\n");
+    ok = true;
+    if ((stat = flash_unlock(flash_test_start, 
+                             CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) {
+        diag_printf("FLASH: unlock failed: %s\n", flash_errmsg(stat));
+        ok = false;
+    }    
+#endif
+    
     // Erase test
     diag_printf("... Erase test\n");
     ok = true;
     if ((stat = flash_erase(flash_test_start, 
-                            CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != FLASH_ERR_OK) {
+                            CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) {
         diag_printf("FLASH: erase failed: %s\n", flash_errmsg(stat));
         ok = false;
     }    
     if (ok && (stat = flash_read(flash_test_start, (void *)test_buf1,
-                           CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != FLASH_ERR_OK) {
+                           CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) {
         diag_printf("FLASH: read/verify after erase failed: %s\n", flash_errmsg(stat));
         ok = false;
     }    
     lp1 = (cyg_uint32 *)test_buf1;
     for (i = 0;  i < CYGNUM_IO_FLASH_TEST_LENGTH;  i += sizeof(cyg_uint32)) {
@@ -148,11 +170,11 @@ cyg_start( void )
     }
     // Try reading in little pieces
     len = CYGNUM_IO_FLASH_TEST_LENGTH;
     flash_addr = flash_test_start;
     while (len > 0) {
-        if ((stat = flash_read(flash_addr, (void *)test_buf1, 0x200, &err_addr)) != FLASH_ERR_OK) {
+        if ((stat = flash_read(flash_addr, (void *)test_buf1, 0x200, &err_addr)) != CYG_FLASH_ERR_OK) {
             diag_printf("FLASH: read[short]/verify after erase failed: %s\n", flash_errmsg(stat));
             ok = false;
             break;
         }    
         flash_addr = (cyg_uint8 *)flash_addr + 0x200;
@@ -182,16 +204,16 @@ cyg_start( void )
         *lp1 = (cyg_uint32)lp1;
         lp1++;
     }
     ok = true;
     if (ok && (stat = flash_program(flash_test_start, (void *)test_buf1,
-                                    CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != FLASH_ERR_OK) {
+                                    CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) {
         diag_printf("FLASH: write failed: %s\n", flash_errmsg(stat));
         ok = false;
     }    
     if (ok && (stat = flash_read(flash_test_start, (void *)test_buf2,
-                                    CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != FLASH_ERR_OK) {
+                                    CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) {
         diag_printf("FLASH: read/verify after write failed: %s\n", flash_errmsg(stat));
         ok = false;
     }    
     lp1 = (cyg_uint32 *)test_buf1;
     lp2 = (cyg_uint32 *)test_buf2;
@@ -207,11 +229,11 @@ cyg_start( void )
     len = CYGNUM_IO_FLASH_TEST_LENGTH;
     flash_addr = flash_test_start;
     lp1 = (cyg_uint32 *)test_buf1;
     lp2 = (cyg_uint32 *)test_buf2;
     while (len > 0) {
-        if ((stat = flash_read(flash_addr, lp2, 0x200, &err_addr)) != FLASH_ERR_OK) {
+        if ((stat = flash_read(flash_addr, lp2, 0x200, &err_addr)) != CYG_FLASH_ERR_OK) {
             diag_printf("FLASH: read[short]/verify after erase failed: %s\n", flash_errmsg(stat));
             ok = false;
             break;
         }    
         flash_addr = (cyg_uint8 *)flash_addr + 0x200;
@@ -225,18 +247,30 @@ cyg_start( void )
                 len = 0;
                 break;
             }
         }
     }
-
+    
     if (!ok) {
         CYG_TEST_INFO("FLASH write/verify failed");
     }
 
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+    // Lock test
+    diag_printf("... Lock test\n");
+    ok = true;
+    if ((stat = flash_lock(flash_test_start, 
+                           CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) {
+        diag_printf("FLASH: unlock failed: %s\n", flash_errmsg(stat));
+        ok = false;
+    }    
+#endif
+    
     if (passed) {
         CYG_TEST_PASS_FINISH("FLASH test1");
     } else {
         CYG_TEST_FAIL_FINISH("FLASH test1");
     }
 }
+#endif
 
 // EOF flash1.c
Index: packages/io/flash/current/tests/flashdev.c
===================================================================
RCS file: packages/io/flash/current/tests/flashdev.c
diff -N packages/io/flash/current/tests/flashdev.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ packages/io/flash/current/tests/flashdev.c	18 Nov 2008 00:54:13 -0000
@@ -0,0 +1,328 @@
+//=================================================================
+//
+//        flashdev.c
+//
+//        Simple tests for FLASHdev driver
+//
+//=================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 Gary Thomas
+// Copyright (C) 2004, 2005, 2006, 2008 eCosCentric Limited
+//
+// 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):     nickg, gthomas
+// Contributors:  
+// Date:          2005-10-25
+// Description:   Simple test of FLASH I/O device. This is really
+//                just a copy of the flash1 test, but using the
+//                /dev/flash interface instead of the flash library.
+//
+// Options:
+//####DESCRIPTIONEND####
+//=================================================================
+
+// #define DEBUG_PRINTFS
+
+#include <pkgconf/hal.h>
+#include <pkgconf/io_flash.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+#include <cyg/infra/diag.h>
+#include <cyg/infra/testcase.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/config_keys.h>
+#include <cyg/io/flash.h>
+#include <errno.h>
+#include <string.h>
+#include <cyg/hal/hal_if.h>
+
+//=================================================================
+// Config options.
+
+#define FLASH_TEST_OFFSET 0
+#define FLASH_TEST_LENGTH 0x40000
+
+//=================================================================
+// A FIS entry named "flashtest" of at least FLASH_TEST_LENGTH bytes
+// must exist for this test to work. It can be created with the
+// following command:
+//
+// RedBoot> fis cre -b %{freememlo} -l 0x100000 flashtest
+
+#define FLASH_TEST_DEVICE "/dev/flash/fis/flashtest"
+
+// If it does not exist, a FIS entry named "jffs2test" will be used
+// if present, as this may have been set up for jffs2 testing.
+#define FLASH_TEST_DEVICE2 "/dev/flash/fis/jffs2test"
+
+//=================================================================
+
+#if !defined(CYGPKG_IO_FLASH_BLOCK_DEVICE)
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_NA("Only usable with flash block device driver");
+}
+#else
+
+//=================================================================
+
+externC void
+cyg_start( void )
+{
+    Cyg_ErrNo stat;
+    cyg_io_handle_t flash_handle;
+    cyg_io_flash_getconfig_erase_t e;
+    cyg_io_flash_getconfig_devsize_t d;
+    cyg_io_flash_getconfig_blocksize_t b;
+    cyg_io_flash_getconfig_lock_t l;
+    cyg_io_flash_getconfig_unlock_t u;
+    CYG_ADDRWORD flash_start, flash_end;
+    CYG_ADDRWORD flash_test_start, flash_addr;
+    cyg_uint32 flash_block_size, flash_num_blocks;
+    CYG_ADDRWORD test_buf1, test_buf2;
+    cyg_uint32 *lp1, *lp2;
+    int i, len;
+    cyg_bool passed, ok;
+
+    CYG_TEST_INIT();
+
+    passed = true;
+
+    if ((stat = cyg_io_lookup(FLASH_TEST_DEVICE, &flash_handle)) == -ENOENT) {
+        stat = cyg_io_lookup(FLASH_TEST_DEVICE2, &flash_handle);
+    }
+
+    if (stat != 0) {
+        diag_printf("FLASH: driver init failed: %s\n", strerror(-stat));
+        CYG_TEST_FAIL_FINISH("FLASH driver init failed");
+    }
+
+    len = sizeof(d);
+    stat = cyg_io_get_config( flash_handle, CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &d, &len );
+    flash_start = 0;
+    // Keep 'end' address as last valid location, to avoid wrap around problems
+    flash_end = d.dev_size - 1;
+
+    len = sizeof(b);
+    b.offset = 0;
+    stat = cyg_io_get_config( flash_handle, CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &b, &len );
+    flash_block_size = b.block_size;
+    flash_num_blocks = d.dev_size/flash_block_size;
+
+    diag_printf("FLASH: %p - %p, %d blocks of 0x%x bytes each.\n", 
+                (void*)flash_start, (void*)(flash_end + 1), flash_num_blocks, flash_block_size);
+
+    // Verify that the testing limits are within the bounds of the
+    // physical device.  Also verify that the size matches with
+    // the erase block size on the device
+    if ((FLASH_TEST_OFFSET > (flash_end - flash_start)) ||
+        ((FLASH_TEST_OFFSET + FLASH_TEST_LENGTH) > (flash_end - flash_start))) {
+        CYG_TEST_FAIL_FINISH("FLASH test region outside physical limits");
+    }
+    if ((FLASH_TEST_LENGTH % flash_block_size) != 0) {
+        CYG_TEST_FAIL_FINISH("FLASH test region must be integral multiple of erase block size");
+    }
+
+    // Allocate two buffers large enough for the test
+    test_buf1 = (CYG_ADDRWORD)CYGMEM_SECTION_heap1;
+    test_buf2 = test_buf1 + FLASH_TEST_LENGTH;
+    if (CYGMEM_SECTION_heap1_SIZE < (FLASH_TEST_LENGTH * 2)) {
+        CYG_TEST_FAIL_FINISH("FLASH not enough heap space - reduce size of test region");
+    }
+    diag_printf("... Using test buffers at %p and %p\n", (void *)test_buf1, (void *)test_buf2);
+    flash_test_start = flash_start + FLASH_TEST_OFFSET;
+
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+    // Unlock test
+    diag_printf("... Unlock test\n");
+    ok = true;
+    u.offset = flash_test_start;
+    u.len = FLASH_TEST_LENGTH;
+    len = sizeof(u);
+    if ((stat = cyg_io_get_config(flash_handle, CYG_IO_GET_CONFIG_FLASH_UNLOCK, &u, &len ) ) != 0 || u.flasherr != 0)
+    {
+        diag_printf("FLASH: unlock failed: %s %s\n", strerror(stat), cyg_flash_errmsg(u.flasherr));
+        ok = false;
+    }
+#endif
+    
+    // Erase test
+    diag_printf("... Erase test\n");
+    ok = true;
+
+    e.offset = flash_test_start;
+    e.len = FLASH_TEST_LENGTH;
+    len = sizeof(e);
+    if ((stat = cyg_io_get_config(flash_handle, CYG_IO_GET_CONFIG_FLASH_ERASE, &e, &len ) ) != 0 || e.flasherr != 0)
+    {
+        diag_printf("FLASH: erase failed: %s %s\n", cyg_flash_errmsg(stat),cyg_flash_errmsg(e.flasherr));
+        ok = false;
+    }
+    len = FLASH_TEST_LENGTH;
+    if (ok && (stat = cyg_io_bread(flash_handle, (void *)test_buf1, &len, flash_test_start)) != 0)
+    {
+        diag_printf("FLASH: read/verify after erase failed: %s\n", cyg_flash_errmsg(stat));
+        ok = false;
+    }    
+    lp1 = (cyg_uint32 *)test_buf1;
+    for (i = 0;  i < FLASH_TEST_LENGTH;  i += sizeof(cyg_uint32)) {
+        if (*lp1++ != 0xFFFFFFFF) {
+            diag_printf("FLASH: non-erased data found at offset %p\n", (void*)((CYG_ADDRWORD)(lp1-1) - test_buf1));
+            diag_dump_buf((void *)(lp1-1), 32);
+            ok = false;
+            break;
+        }
+    }
+
+    // Try reading in little pieces
+    len = FLASH_TEST_LENGTH;
+    flash_addr = flash_test_start;
+    while (len > 0) {
+        cyg_uint32 l = 0x200;
+        if ((stat = cyg_io_bread(flash_handle, (void *)test_buf1, &l, flash_addr)) != CYG_FLASH_ERR_OK) {
+            diag_printf("FLASH: read[short]/verify after erase failed: %s\n", strerror(stat));
+            ok = false;
+            break;
+        }    
+        flash_addr = flash_addr + l;
+        len -= l;
+        lp1 = (cyg_uint32 *)test_buf1;
+        for (i = 0;  i < 0x200;  i += sizeof(cyg_uint32)) {
+            if (*lp1++ != 0xFFFFFFFF) {
+                diag_printf("FLASH: non-erased data found at offset %p\n", 
+                            (cyg_uint8 *)flash_addr + (CYG_ADDRWORD)((lp1-1) - test_buf1));
+                diag_dump_buf((void *)(lp1-1), 32);
+                ok = false;
+                len = 0;
+                break;
+            }
+        }
+    }
+    
+    if (!ok) {
+        CYG_TEST_INFO("FLASH erase failed");
+        passed = false;
+    }
+
+    // Simple write/verify test
+    diag_printf("... Write/verify test\n");
+    lp1 = (cyg_uint32 *)test_buf1;
+    for (i = 0;  i < FLASH_TEST_LENGTH;  i += sizeof(cyg_uint32)) {
+        *lp1 = (cyg_uint32)lp1;
+        lp1++;
+    }
+    ok = true;
+    len = FLASH_TEST_LENGTH;
+    if (ok && (stat = cyg_io_bwrite(flash_handle, (void *)test_buf1,
+                                    &len, flash_test_start)) != 0) {
+        diag_printf("FLASH: write failed: %s\n", strerror(stat));
+        ok = false;
+    }
+
+
+    len = FLASH_TEST_LENGTH;
+    if (ok && (stat = cyg_io_bread(flash_handle,  (void *)test_buf2, &len, flash_test_start)) != CYG_FLASH_ERR_OK) {
+        diag_printf("FLASH: read/verify after write failed: %s\n", strerror(stat));
+        ok = false;
+    }    
+    lp1 = (cyg_uint32 *)test_buf1;
+    lp2 = (cyg_uint32 *)test_buf2;
+    for (i = 0;  i < FLASH_TEST_LENGTH;  i += sizeof(cyg_uint32)) {
+        if (*lp2++ != *lp1++) {
+            diag_printf("FLASH: incorrect data found at offset %p\n", (void *)((CYG_ADDRWORD)(lp2-1) - test_buf2));
+            diag_dump_buf((void *)(lp2-1), 32);
+            ok = false;
+            break;
+        }
+    }
+
+    // Try reading in little pieces
+    len = FLASH_TEST_LENGTH;
+    flash_addr = flash_test_start;
+    lp1 = (cyg_uint32 *)test_buf1;
+    lp2 = (cyg_uint32 *)test_buf2;
+    while (len > 0) {
+        cyg_uint32 l = 0x200;
+        if ((stat = cyg_io_bread(flash_handle, (void *)lp2, &l, flash_addr)) != 0) {
+            diag_printf("FLASH: read[short]/verify after erase failed: %s\n", strerror(stat));
+            ok = false;
+            break;
+        }    
+        flash_addr = flash_addr + l;
+        len -= l;
+        for (i = 0;  i < l;  i += sizeof(cyg_uint32)) {
+            if (*lp2++ != *lp1++) {
+                diag_printf("FLASH: incorrect data found at offset %p\n", 
+                            (cyg_uint8 *)flash_addr + (CYG_ADDRWORD)((lp2-1) - test_buf2));
+                diag_dump_buf((void *)(lp2-1), 32);
+                ok = false;
+                len = 0;
+                break;
+            }
+        }
+    }
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+    // Lock test
+    diag_printf("... Lock test\n");
+    ok = true;
+    l.offset = flash_test_start;
+    l.len = FLASH_TEST_LENGTH;
+    len = sizeof(l);
+    if ((stat = cyg_io_get_config(flash_handle, CYG_IO_GET_CONFIG_FLASH_LOCK, &l, &len ) ) != 0 || l.flasherr != 0 )
+    {
+        diag_printf("FLASH: unlock failed: %s %s\n", strerror(stat), cyg_flash_errmsg(l.flasherr));
+        ok = false;
+    }
+#endif
+    
+    if (!ok) {
+        CYG_TEST_INFO("FLASH write/verify failed");
+    }
+
+    if (passed) {
+        CYG_TEST_PASS_FINISH("FLASH test1");
+    } else {
+        CYG_TEST_FAIL_FINISH("FLASH test1");
+    }
+}
+#endif
+
+//=================================================================
+// EOF flashdev.c

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]