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: Flash device interface


On Dienstag, 4. November 2003 16:57, Roland Caßebohm wrote:
> Hi again,
>
> I'm just trying to use the flash device interface (/dev/flash1)
> for accessing flash, but if I write to flash with write() I get
> an "I/O error".
>
> The problem seems to be, that flashiodev_bwrite() does not erase
> the region before programming it. I also think about a possibility
> to write regions, which are not block aligned.
>
> Maybe the function calls flash_erase() and flash_program() block
> by block and for the first and the last block which are not block
> aligned, it first makes a copy of the current flash content,
> replaces the to be written data in this copy and programs the copy
> back.
>
> I also want to use flash_read() instead of directly read the flash.
> Then it should work with flashes with indirect access too.
>
> Any suggestions?

In the attached patch I have made such a change, but as I have written
in an other mail the devfs which is used by this layer doesn't support
lseek() and fstat(). That's why it is even with this changes not
possible to use a flash image like a file.

But at least erasing the flash before writing it should be done,
else the flash content would be corrupted.

Roland
Index: io/flash/current/src/flashiodev.c
===================================================================
RCS file: /home/cassebohm/net/USERS/CVSROOT/VSprojects/ecos/packages/io/flash/current/src/flashiodev.c,v
retrieving revision 1.1.1.1
diff -u -5 -p -r1.1.1.1 flashiodev.c
--- io/flash/current/src/flashiodev.c	29 Sep 2003 15:15:55 -0000	1.1.1.1
+++ io/flash/current/src/flashiodev.c	5 Nov 2003 15:12:26 -0000
@@ -119,49 +119,160 @@ flashiodev_lookup( struct cyg_devtab_ent
 
 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;
+    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;
+    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, dev->end);
     if ( startpos < dev->start )
         return -EINVAL;
     if ( endpos > flashend )
         return -EINVAL;
 #endif
 
-    memcpy( buf, startpos, *len );
-    return ENOERR;
+    err = flash_read( startpos, 
+                     (void *)buf, *len, &erraddr );
+
+    if ( err )
+        err = -EIO; // just something sane
+    return err;
 } // flashiodev_bread()
 
+//FIXME: Must be generic, but how? don't want to use malloc.
+#define CYGNUM_IO_FLASH_BLOCK_BLOCKSIZE 0x1000
+static char flashiodev_buffer[CYGNUM_IO_FLASH_BLOCK_BLOCKSIZE];
+
 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;
+    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;
+    char *startpos = dev->start + 32; //pos;
+    cyg_uint32 tlen=*len;
+    cyg_uint32 blen;
+    char *tbuf = (char *)buf;
 
 #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
     char *endpos = startpos + *len - 1;
     char *flashend = MIN( (char *)flash_info.end, dev->end);
     if ( startpos < dev->start )
         return -EINVAL;
     if ( endpos > flashend )
         return -EINVAL;
 #endif
-    err = flash_program( startpos, 
-                         (void *)buf, *len, &erraddr );
+
+    // if not block aligned
+    if ((CYG_ADDRESS)startpos & ~flash_info.block_mask)
+    {
+        char *bstartaddr;
+        char *bendaddr;
+        char *block;
+
+        // make a copy of the block
+        block = (char *)((CYG_ADDRESS)startpos & flash_info.block_mask);
+        err = flash_read(block, flashiodev_buffer, 
+                    flash_info.block_size, &erraddr);
+        if (err)
+            goto out;
+
+        // calculate the region in the copy to be replaced
+        if ( (startpos + tlen) < (block + flash_info.block_size) )
+            bendaddr = flashiodev_buffer + ((CYG_ADDRESS)(startpos + 
+                    tlen)  & ~flash_info.block_mask);
+        else
+            bendaddr = flashiodev_buffer + flash_info.block_size;
+
+        bstartaddr = flashiodev_buffer + ((CYG_ADDRESS)startpos 
+                    & ~flash_info.block_mask);
+        blen=bendaddr-bstartaddr;
+
+        // replace the region
+        memcpy(bstartaddr, tbuf, blen);
+
+        // erase the whole block
+        err = flash_erase(block,  
+                    flash_info.block_size, &erraddr);
+        if (err)
+            goto out;
+
+        // reflash the block
+        err = flash_program(block, flashiodev_buffer, 
+                    flash_info.block_size, &erraddr);
+        if (err)
+            goto out;
+
+        tlen -= blen;
+        startpos += blen;
+        tbuf += blen;
+    }
+   
+    // if there is data left
+    if ( tlen == 0)
+            goto out;
+
+    // startpos is aligned now, aligne endpos now
+    blen = tlen & flash_info.block_mask;
+
+    // Flash all aligned blocks
+    if (blen)
+    {
+        err = flash_erase(startpos, blen, &erraddr);
+        if (err)
+            goto out;
+
+        err = flash_program(startpos, tbuf, blen, &erraddr);
+        if (err)
+            goto out;
+
+        tlen -= blen;
+        startpos += blen;
+        tbuf += blen;
+    }
+        
+    // if there is an unaligned rest
+    if ( tlen > 0)
+    {
+        // make a copy of the block
+        err = flash_read(startpos, flashiodev_buffer, 
+                    flash_info.block_size, &erraddr);
+        if (err)
+            goto out;
+
+        // replace the region
+        memcpy(flashiodev_buffer, tbuf, tlen);
+
+        // erase the whole block
+        err = flash_erase(startpos,  
+                    flash_info.block_size, &erraddr);
+        if (err)
+            goto out;
+
+        // reflash the block
+        err = flash_program(startpos, flashiodev_buffer, 
+                    flash_info.block_size, &erraddr);
+        if (err)
+            goto out;
+
+        tlen = 0;
+        startpos += tlen;
+        tbuf += tlen;
+    }
+
+out:
+    *len -= tlen;
 
     if ( err )
         err = -EIO; // just something sane
     return err;
 } // flashiodev_bwrite()

-- 
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]