This is the mail archive of the ecos-discuss@sources.redhat.com 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]

Re: Supporting Paged Flash in eCos/RedBoot


Ian Campbell wrote:
Hi,

Attached is a rough first draft of a patch to implement an improved
flash interface -- It's a first pass and I certainly wouldn't expect you
to apply it as is...

The main bulk of the patch modifies the API of cyg/io/flash.h such that
each function takes a struct flash_info * as it's first parameter and
all addresses are described as unsigned long offsets

NB The flash drivers were written when Gary thought he could get away with using things like ints and longs instead of the normal eCos-y types like cyg_uint32 etc. Since we'd want to support flash drivers in eCos, it would be good for proper portability to use e.g. CYG_ADDRESS for addresses. In saying that, unsigned longs are okay for just offsets, although a typedef'd type might be cunning.


It would also be brilliant if the functions had a "cyg_" prefix on the front and not just "flash_". Otherwise the namespace gets polluted and it only takes a user to have a global in their app called "int flash_program;" for weird stuff to happen , or the link to fail :-). We can add #define's for the existing API functions in flash.h for e.g. flash_init to cyg_flash_init, for backwards compatibility, on the assumption that these will go away "soon".

If this is too much right for you to do, we can revisit this before making this API "official". Incidentally, while it's still work in progress, we should probably even keep the existing drivers (and redboot flash.c) working the same way. That can be by just renaming the files to flash_erase_block2.c etc. all depending on that CDL interface setting, or in the case of the strata flash driver, a configuration option so the user can set it so we don't break systems relying on the old driver. But don't worry about that for now - we can copy the files when it's closer to completion... otherwise the diffs won't be helpful :-).

So, comments?

Many, as I'm sure you were expecting :-)... It's good stuff so far though...


Index: devs/flash/intel/strata/current/src/flash_erase_block.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/flash_erase_block.c,v
retrieving revision 1.4
diff -u -b -B -w -p -u -r1.4 flash_erase_block.c
--- devs/flash/intel/strata/current/src/flash_erase_block.c 23 May 2002 23:01:02 -0000 1.4
+++ devs/flash/intel/strata/current/src/flash_erase_block.c 21 Feb 2003 13:33:53 -0000
@@ -56,19 +56,19 @@
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_cache.h>
+#include <cyg/io/flash.h>
+
//
// CAUTION! This code must be copied to RAM before execution. Therefore,
// it must not contain any code which might be position dependent!
//
-
-int flash_erase_block(volatile flash_t *block, unsigned int block_size)
+int flash_erase_block(struct flash_info *flash_info, unsigned long block, unsigned int block_size)

IMHO The hardware driver should already be perfectly aware what size the block is :-), so that needn't be passed in.


int
-flash_program_buf(volatile flash_t *addr, flash_t *data, int len,
+flash_program_buf(struct flash_info *flash_info, + unsigned long offset, flash_t *data, int len,
unsigned long block_mask, int buffer_size)

I've never liked that block_mask thing. Again the driver should already know what's needed. This is particularly relevant if the data written straddles a boundary where the block size changes.


 int
-flash_unlock_block(volatile flash_t *block, int block_size, int blocks)
+flash_unlock_block(struct flash_info *flash_info, unsigned long block, unsigned long block_size, int blocks)

Again block_size needn't be psased in. In other drivers then it's more likely the right thing happens if a block size boundary is straddled.


Index: devs/flash/intel/strata/current/src/strata.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/strata.c,v
retrieving revision 1.7
diff -u -b -B -w -p -u -r1.7 strata.c
--- devs/flash/intel/strata/current/src/strata.c 23 May 2002 23:01:02 -0000 1.7
+++ devs/flash/intel/strata/current/src/strata.c 21 Feb 2003 13:33:53 -0000
@@ -67,31 +67,53 @@ extern void diag_dump_buf(void *buf, CYG
extern int strncmp(const char *s1, const char *s2, size_t len);
extern void *memcpy( void *, const void *, size_t );
+#ifndef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM
+// 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;
+}
+#endif

About time this stuff got added to the strataflash driver. Great!


int
-flash_hwr_init(void)
+flash_hwr_init(struct flash_info *flash_info)
{
@@ -138,30 +160,34 @@ flash_hwr_init(void)
}
#endif // Not CYGOPT_FLASH_IS_BOOTBLOCK
- flash_info.block_size = region_size*CYGNUM_FLASH_DEVICES;
- flash_info.buffer_size = buffer_size;
- flash_info.blocks = num_regions;
- flash_info.start = (void *)CYGNUM_FLASH_BASE;
- flash_info.end = (void *)(CYGNUM_FLASH_BASE +
- (num_regions*region_size*CYGNUM_FLASH_DEVICES));
-#ifdef CYGNUM_FLASH_BASE_MASK
+ flash_info->block_size = region_size*CYGNUM_FLASH_DEVICES;
+ flash_info->buffer_size = buffer_size;
+ flash_info->blocks = num_regions*CYGNUM_FLASH_BANKS;
+#if 0 // IJC
+ flash_info->start = (void *)CYGNUM_FLASH_BASE;
+ flash_info->end = (void *)(CYGNUM_FLASH_BASE +
+ (num_regions*region_size*CYGNUM_FLASH_DEVICES*CYGNUM_FLASH_BANKS));
+#endif
+ flash_info->size = (num_regions*region_size*CYGNUM_FLASH_DEVICES*CYGNUM_FLASH_BANKS);
+
+#ifdef CYGNUM_FLASH_BASE_MASK_DISABLE // IJC -- what does this do?


Hmm... now what if a flash driver is for a flash with bootblocks? Or any other device with different block sizes. We'd need to specify multiple block sizes. Also specifying a count of blocks wouldn't be helpful in that context.

This came up before with the AT91 flash, and I tried to do something to get that working. Just in case it's a useful starting point, I've attached a patch for io/flash that was meant to support variable block sizes better. It's against the repository version not yours I'm afraid. In particular struct flash_info would now contain a block table, with entries describing the size. I never completed the work (doesn't help when you have no hardware!), so the patch is yours to do with as you will :-). I would (obviously) recommend this approach though.

Index: devs/flash/intel/strata/current/src/strata.h
+// ------------------------------------------------------------------------
+
+#ifndef HAL_FLASH_READ
+#define HAL_FLASH_READ(__OFFSET__, __VALUE__) 					\
+CYG_MACRO_START									\
+__VALUE__ = *(volatile flash_t *)(cyg_uint8*)FLASH_P2V(CYGNUM_FLASH_BASE)+(__OFFSET__));\
+CYG_MACRO_END
+#endif
+
+#ifndef HAL_FLASH_WRITE
+#define HAL_FLASH_WRITE(__OFFSET__, __VALUE__) 					\
+CYG_MACRO_START									\
+*(volatile flash_t *)((cyg_uint8*)FLASH_P2V(CYGNUM_FLASH_BASE)+(__OFFSET__)) = (__VALUE__); \
+CYG_MACRO_END
+#endif
+

If these are defined in the flash driver, they aren't really HAL macros wanting the HAL prefix. That would confuse people as to where they are defined. May I suggest CYGHWR_FLASH_READ and CYGHWR_FLASH_WRITE perhaps?


[snip io/flash/current/src/flash.c]
There's plenty of stuff in flash.c to munge to get rid of the reliance on fixed block sizes and block masks.


[snip redboot/current/src/flash.c]

At this point I wouldn't try to get redboot working with the multiple block sizes aspect of the API - save that challenge to another day as it requires quite a rethink of this file. What's important is that the underlying API in io/flash is capable of it.

This is all good stuff, and is definitely going the right way. You've obviously also been very productive!

Great work,

Jifl
--
eCosCentric    http://www.eCosCentric.com/    The eCos and RedBoot experts
--[ "You can complain because roses have thorns, or you ]--
--[  can rejoice because thorns have roses." -Lincoln   ]-- Opinions==mine
? flash.at91.dead.patch
Index: cdl/io_flash.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/cdl/io_flash.cdl,v
retrieving revision 1.11
diff -u -5 -p -r1.11 io_flash.cdl
--- cdl/io_flash.cdl	23 May 2002 23:06:14 -0000	1.11
+++ cdl/io_flash.cdl	14 Feb 2003 01:17:11 -0000
@@ -104,10 +104,19 @@ cdl_package CYGPKG_IO_FLASH {
         description   "
             This option will be enabled by devices which can support
             locking (write-protection) of individual blocks."
     }
 
+    cdl_interface CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE {
+        display       "Hardware has variable block sizes"
+        flavor        booldata
+        description   "
+            This option is enabled when a flash device and its driver
+            have variable block sizes, i.e. different block sizes for
+            different regions of the flash device."
+    }
+
     cdl_option CYGSEM_IO_FLASH_VERIFY_PROGRAM {
         display          "Verify data programmed to flash"
         flavor           bool
         default_value    1
         description      "
Index: include/flash.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/include/flash.h,v
retrieving revision 1.15
diff -u -5 -p -r1.15 flash.h
--- include/flash.h	23 May 2002 23:06:14 -0000	1.15
+++ include/flash.h	14 Feb 2003 01:17:11 -0000
@@ -56,10 +56,18 @@
 #include <pkgconf/io_flash.h>
 #include <cyg/hal/hal_cache.h>
 
 typedef int _printf(const char *fmt, ...);
 
+struct flash_block_table_entry {
+    void           *offset_addr; // offset of this address from the start of
+                                 // the flash device's base address
+    unsigned long  size;         // size of this region
+    unsigned long  block_size;   // size of blocks in this region
+    // potential for expansion in future...
+};
+
 #define FLASH_MIN_WORKSPACE CYGNUM_FLASH_WORKSPACE_SIZE  // Space used by FLASH code
 
 externC int flash_init(void *work_space, int work_space_length, _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);
@@ -68,10 +76,22 @@ externC void flash_dev_query(void *data)
 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);
+
+// flash_block_size() returns -ve error code on error, or block size for
+// address on success
+externC int flash_block_size( void *address ); 
+
+// flash_get_block_table() returns a block table used by the driver giving
+// definitions of block sizes. The address argument is used to indicate
+// which device when in the future multiple devices are supported.
+externC int flash_get_block_table( void *flash_at_address,
+                                   const struct flash_block_table_entry **table);
+
+// flash_get_block_info() is deprecated.
 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);
 
 #define FLASH_ERR_OK              0x00  // No error - operation complete
@@ -111,14 +131,18 @@ typedef struct {
 #ifdef _FLASH_PRIVATE_
 
 struct flash_info {
     void *work_space;
     int   work_space_size;
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    const struct flash_block_table_entry *block_table;
+#else
     int   block_size;   // Assuming fixed size "blocks"
     int   blocks;       // Number of blocks
+    unsigned long block_mask; // ~(block_size-1)
+#endif
     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;
 };
 
Index: src/flash.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/src/flash.c,v
retrieving revision 1.20
diff -u -5 -p -r1.20 flash.c
--- src/flash.c	23 May 2002 23:06:16 -0000	1.20
+++ src/flash.c	14 Feb 2003 01:17:11 -0000
@@ -82,11 +82,13 @@ flash_init(void *work_space, int work_sp
     flash_info.work_space = work_space;
     flash_info.work_space_size = work_space_size;
     if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
         return err;
     }
+#ifndef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
     flash_info.block_mask = ~(flash_info.block_size-1);
+#endif
     flash_info.init = 1;
     return FLASH_ERR_OK;
 }
 
 #ifndef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM
@@ -155,17 +157,76 @@ flash_get_limits(void *target, void **st
     *end = flash_info.end;
     return FLASH_ERR_OK;
 }
 
 int
+flash_block_size( void *address )
+{
+    if (!flash_info.init) {
+        return -FLASH_ERR_NOT_INIT;
+    }
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    if ( address < flash_info.start || address >= flash_info.end )
+        return -FLASH_ERR_INVALID;
+    {
+        struct flash_block_table_entry *t = flash_info.block_table;
+        CYG_ADDRESS offset = (CYG_ADDRESS)address - (CYG_ADDRESS)flash_info.start;
+        while (t->offset_addr < offset) {
+            if (t->size == 0) // reached end of table. Hmm. This shouldn't
+                              // happen though given the address check above.
+              return -FLASH_ERR_INVALID;
+        }
+        return t->block_size;
+    }
+#else
+    return flash_info.block_size;
+#endif
+}
+
+int flash_get_block_table( void *flash_at_address,
+                           const struct flash_block_table_entry **table )
+{
+    if (!flash_info.init) {
+        return FLASH_ERR_NOT_INIT;
+    }
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    // flash_at_address ignored for now
+    *table = flash_info.block_table;
+#else
+    {
+        // make a block table up
+        static struct flash_block_table_entry flash_fixed_block_table[2];
+        if (flash_fixed_block_table[0].size == 0) {
+            flash_fixed_block_table[0].offset_addr = NULL;
+            flash_fixed_block_table[0].size = flash_info.block_size * flash_info.blocks;
+            flash_fixed_block_table[0].block_size = flash_info.block_size;
+        }
+        *table = flash_fixed_block_table;
+    }
+#endif
+    return FLASH_ERR_OK;    
+} // flash_get_block_table()
+
+
+int
 flash_get_block_info(int *block_size, int *blocks)
 {
     if (!flash_info.init) {
         return FLASH_ERR_NOT_INIT;
     }
+    diag_printf("Warning, flash_get_block_info() is deprecated.\n");
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    // may as well pick something
+    *block_size = flash_block_size( flash_info.start );
+    if (*block_size < 0)
+        return -FLASH_ERR_INVALID;
+    *blocks = -1; // it's just tough. This makes no sense for variable
+                  // block sizes.
+#else
     *block_size = flash_info.block_size;
     *blocks = flash_info.blocks;
+#endif
     return FLASH_ERR_OK;
 }
 
 int
 flash_erase(void *addr, int len, void **err_addr)
@@ -173,10 +234,12 @@ flash_erase(void *addr, int len, void **
     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;
+    int block_size;
+    unsigned long block_mask;
 
     if (!flash_info.init) {
         return FLASH_ERR_NOT_INIT;
     }
 
@@ -200,11 +263,21 @@ flash_erase(void *addr, int len, void **
         externC code_fun flash_erase_block;
         _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block);
     }
 #endif
 
-    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    block_size = flash_block_size( addr );
+    if ( block_size < 0 ) {
+        *err_addr = addr;
+        return -block_size; // error code is -ve value
+    }
+    block_mask = ~(block_size-1);
+#else
+    block_mask = flash_info.block_mask;
+#endif
+    block = (unsigned short *)((CYG_ADDRESS)addr & 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);
@@ -220,27 +293,35 @@ flash_erase(void *addr, int len, void **
         unsigned char *dp;
         bool erased = true;
         unsigned short *tmp_block;
 
         dp = (unsigned char *)block;
-        for (i = 0;  i < flash_info.block_size;  i++) {
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+        block_size = flash_block_size( block );
+        if ( block_size < 0 ) {
+            err_addr = (void *)block;
+            stat = -block_size; // error code is -ve value
+            break;
+        }
+#endif
+        for (i = 0;  i < block_size;  i++) {
             if (*dp++ != (unsigned char)0xFF) {
                 erased = false;
                 break;
             }
         }
         if (!erased) {
-            stat = (*_flash_erase_block)(block, flash_info.block_size);
+            stat = (*_flash_erase_block)(block, 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);
+        tmp_block = block + block_size / sizeof(*block);
         if(tmp_block < block){
             // If block address overflows, set block value to end on this loop
             block = end_addr;
         }
         else{
@@ -263,10 +344,12 @@ flash_program(void *_addr, void *_data, 
     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;
+    int block_size;
+    unsigned long block_mask;
 
     if (!flash_info.init) {
         return FLASH_ERR_NOT_INIT;
     }
 
@@ -292,25 +375,38 @@ flash_program(void *_addr, void *_data, 
 #endif
 
     (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data, 
                      (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
 
+#ifndef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    block_size = flash_info.block_size;
+    block_mask = flash_info.block_mask;
+#endif
     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
     FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
     while (len > 0) {
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+        block_size = flash_block_size( addr );
+        if (block_size < 0) {
+            stat = -block_size; // error code is -ve value
+            *err_addr = (void *)addr;
+            break;
+        }
+        block_mask = ~(block_size-1);
+#endif
         size = len;
-        if (size > flash_info.block_size) size = flash_info.block_size;
+        if (size > block_size) size = block_size;
 
-        tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
+        tmp = (CYG_ADDRESS)addr & block_mask;
         if (tmp) {
-                tmp = flash_info.block_size - tmp;
+                tmp = block_size - tmp;
                 if (size>tmp) size = tmp;
 
         }
 
         stat = (*_flash_program_buf)(addr, data, size, 
-                                     flash_info.block_mask, flash_info.buffer_size);
+                                     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;
@@ -340,10 +436,12 @@ flash_lock(void *addr, int len, void **e
     unsigned short *block, *end_addr;
     int stat = 0;
     typedef int code_fun(unsigned short *);
     code_fun *_flash_lock_block;
     int d_cache, i_cache;
+    int block_size;
+    unsigned long block_mask;
 
     if (!flash_info.init) {
         return FLASH_ERR_NOT_INIT;
     }
 
@@ -366,11 +464,21 @@ flash_lock(void *addr, int len, void **e
         externC code_fun flash_lock_block;
         _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block);
     }
 #endif
 
-    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    block_size = flash_block_size( addr );
+    if ( block_size < 0 ) {
+        *err_addr = addr;
+        return -block_size; // error code is -ve value
+    }
+    block_mask = ~(block_size-1);
+#else
+    block_mask = flash_info.block_mask;
+#endif
+    block = (unsigned short *)((CYG_ADDRESS)addr & 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);
@@ -387,12 +495,20 @@ flash_lock(void *addr, int len, void **e
         if (stat) {
             *err_addr = (void *)block;
             break;
         }
 
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+        block_size = flash_block_size( block );
+        if (block_size < 0) {
+            stat = -block_size; // error code is -ve value
+            *err_addr = (void *)block;
+            break;
+        }
+#endif
         // Check to see if block will overflow
-        tmp_block = block + flash_info.block_size / sizeof(*block);
+        tmp_block = block + block_size / sizeof(*block);
         if(tmp_block < block){
             // If block address overflows, set block value to end on this loop
             block = end_addr;
         }
         else{
@@ -412,10 +528,12 @@ flash_unlock(void *addr, int len, void *
     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;
+    int block_size;
+    unsigned long block_mask;
 
     if (!flash_info.init) {
         return FLASH_ERR_NOT_INIT;
     }
 
@@ -438,11 +556,21 @@ flash_unlock(void *addr, int len, void *
         externC code_fun flash_unlock_block;
         _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block);
     }
 #endif
 
-    block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+    block_size = flash_block_size( addr );
+    if ( block_size < 0 ) {
+        *err_addr = addr;
+        return -block_size; // error code is -ve value
+    }
+    block_mask = ~(block_size-1);
+#else
+    block_mask = flash_info.block_mask;
+#endif
+    block = (unsigned short *)((CYG_ADDRESS)addr & 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);
@@ -452,18 +580,32 @@ flash_unlock(void *addr, int len, void *
 
     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);
+        
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+        block_size = flash_block_size( block );
+        if (block_size < 0) {
+            stat = -block_size; // error code is -ve value
+            *err_addr = (void *)block;
+            break;
+        }
+        // flash device drivers should know their own size, but we can't change
+        // the interface to existing drivers easily. We have to wait for some
+        // big flash driver overhaul to have an excuse to fix this.
+        stat = (*_flash_unlock_block)(block, block_size, 0);
+#else
+        stat = (*_flash_unlock_block)(block, block_size, flash_info.blocks);
+#endif
         stat = flash_hwr_map_error(stat);
         if (stat) {
             *err_addr = (void *)block;
             break;
         }
 
-        tmp_block = block + flash_info.block_size / sizeof(*block);
+        tmp_block = block + block_size / sizeof(*block);
         if(tmp_block < block){
             // If block address overflows, set block value to end on this loop
             block = end_addr;
         }
         else{
Index: src/flashiodev.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/src/flashiodev.c,v
retrieving revision 1.2
diff -u -5 -p -r1.2 flashiodev.c
--- src/flashiodev.c	23 May 2002 23:06:16 -0000	1.2
+++ src/flashiodev.c	14 Feb 2003 01:17:11 -0000
@@ -195,13 +195,29 @@ flashiodev_get_config( cyg_io_handle_t h
         if ( startpos > flashend )
             return -EINVAL;
 #endif  
         if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) )
              return -EINVAL;
-        
-        // offset unused for now
+
+#ifdef CYGINT_IO_FLASH_VARIABLE_BLOCK_SIZE
+        {
+            struct flash_block_table_entry *t = flash_info.block_table;
+            CYG_ADDRESS realoffset = CYGNUM_IO_FLASH_BLOCK_OFFSET_1 + b->offset;
+
+            // we've already checked above whether it's in flash at all.
+
+            while (t->offset_addr < realoffset)
+              {
+                if (t->size == 0) // reached end of table. Hmm. This shouldn't
+                                  // happen though.
+                  return -EINVAL;
+              }
+            b->block_size = t->block_size;
+        }
+#else        
 	b->block_size = flash_info.block_size;
+#endif
         return ENOERR;
     }
 
     default:
         return -EINVAL;

-- 
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss

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