diff packages/devs/flash/synthv2/current/src/synth.c @ 1702:0673c75f3a08

Import the first version of the synth flash driver which uses the V2 API.
author asl
date Thu, 05 Aug 2004 13:25:32 +0000
parents
children a24dbf2587a3
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/devs/flash/synthv2/current/src/synth.c
@@ -0,0 +1,291 @@
+//==========================================================================
+//
+//      synth.c
+//
+//      Flash programming
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// 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.
+//
+// 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@ascom.ch
+// Contributors: jlarmour
+// Date:         2001-10-30
+// Purpose:      
+// Description:  
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/devs_flash_synth_v2.h>
+
+#include <cyg/hal/hal_io.h>
+#include <cyg/infra/cyg_ass.h>
+#include <string.h>
+
+#define  _FLASH_PRIVATE_
+#include <cyg/io/flash.h>
+#include <cyg/flash/synth.h>
+
+/* Helper function. The Linux system call cannot pass 6 parameters. Instead
+   a structure is filled in and passed as one parameter */
+static int 
+cyg_hal_sys_do_mmap(void *addr, unsigned long length, unsigned long prot, 
+                    unsigned long flags, unsigned long fd, unsigned long off)
+{
+
+    struct cyg_hal_sys_mmap_args args;
+  
+    args.addr = (unsigned long) addr;
+    args.len = length;
+    args.prot = prot = prot;
+    args.flags = flags;
+    args.fd = fd;
+    args.offset = off;
+
+    return (cyg_hal_sys_mmap(&args));
+}           
+
+static int
+synth_flash_init(struct cyg_flash_dev *dev)
+{
+    struct cyg_flash_synth_config *config = dev->config;
+    struct cyg_flash_synth_priv *priv = dev->priv;
+    cyg_flashaddr_t base;
+    int flags=CYG_HAL_SYS_MAP_SHARED;
+    
+    priv->flashfd = 
+        cyg_hal_sys_open(config->filename,
+                         CYG_HAL_SYS_O_RDWR, 
+                         CYG_HAL_SYS_S_IRWXU|CYG_HAL_SYS_S_IRWXG|
+                         CYG_HAL_SYS_S_IRWXO);
+    if (priv->flashfd == -ENOENT) {
+        long w, bytesleft;
+        char buf[128];
+        
+        priv->flashfd = cyg_hal_sys_open(
+            config->filename, 
+            CYG_HAL_SYS_O_RDWR|CYG_HAL_SYS_O_CREAT, 
+            CYG_HAL_SYS_S_IRWXU|CYG_HAL_SYS_S_IRWXG|CYG_HAL_SYS_S_IRWXO);
+        CYG_ASSERT( priv->flashfd >= 0, 
+                    "Opening of the file for the synth flash failed!");
+        // fill with 0xff
+        memset( buf, 0xff, sizeof(buf) );
+        bytesleft = config->block_size * config->blocks +
+            config->boot_block_size * config->boot_blocks;
+
+        while (bytesleft > 0) {
+            int bytesneeded;
+            bytesneeded = bytesleft < sizeof(buf) ?  
+                bytesleft : sizeof(buf);
+            
+            w = cyg_hal_sys_write( priv->flashfd, buf,
+                                   bytesneeded );
+            CYG_ASSERT(w == bytesneeded, 
+                       "initialization of flash file failed");
+            bytesleft -= bytesneeded;
+        } // while
+    }
+    CYG_ASSERT( priv->flashfd >= 0, 
+                "Opening of the file for the synth flash failed!");
+    if ( priv->flashfd <= 0 ) {
+        return CYG_FLASH_ERR_HWR;
+    }
+
+    if (dev->start != 0) {
+        flags |= CYG_HAL_SYS_MAP_FIXED;
+    }
+    base = (cyg_flashaddr_t)cyg_hal_sys_do_mmap( 
+        (void *)dev->start,
+        config->blocks * config->block_size + 
+        config->boot_block_size * config->boot_blocks,
+        CYG_HAL_SYS_PROT_READ, 
+        flags,
+        priv->flashfd, 
+        0l);
+    CYG_ASSERT( (int) base > 0, "mmap of flash file failed!" );
+    if (base <= 0) {
+        return CYG_FLASH_ERR_HWR;
+    }
+    dev->start = base;
+    dev->end = base + (config->blocks * config->block_size) +
+        (config->boot_blocks * config->boot_block_size) - 1;
+    if (config->boot_blocks) {
+        if (config->boot_block_bottom) {
+            priv->block_info[0].block_size = config->boot_block_size;
+            priv->block_info[0].blocks = config->boot_blocks;
+            priv->block_info[1].block_size = config->block_size;
+            priv->block_info[1].blocks = config->blocks;
+        } else {
+            priv->block_info[0].block_size = config->block_size;
+            priv->block_info[0].blocks = config->blocks;
+            priv->block_info[1].block_size = config->boot_block_size;
+            priv->block_info[1].blocks = config->boot_blocks;
+        }
+        dev->num_block_infos = 2;
+    } else {
+        priv->block_info[0].block_size = config->block_size;
+        priv->block_info[0].blocks = config->blocks;
+        dev->num_block_infos = 1;
+    }
+    dev->block_info = &priv->block_info[0];
+
+    return CYG_FLASH_ERR_OK;
+}
+
+// Map a hardware status to a package error
+static int
+synth_flash_hwr_map_error(struct cyg_flash_dev *dev, int err)
+{
+    return err;
+}
+
+/* This helps speed up the erase. */
+static char empty[4096];
+static cyg_bool empty_inited = false;
+
+// Return the size of the block which is at the given address.
+// __inline__ so that we know it will be in RAM, not ROM.
+static __inline__ 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;
+}
+
+static int 
+synth_flash_erase_block(struct cyg_flash_dev *dev, 
+                        const cyg_flashaddr_t block_base)
+{
+#ifdef CYGDBG_USE_ASSERTS
+    struct cyg_flash_synth_config *config = dev->config;
+#endif
+    struct cyg_flash_synth_priv *priv = dev->priv;
+    int offset = (int)block_base;
+    size_t block_size;
+    int i;
+
+    offset -= dev->start;
+    
+    cyg_hal_sys_lseek(priv->flashfd, offset,
+                      CYG_HAL_SYS_SEEK_SET);
+    
+    if (!empty_inited) {
+        memset(empty, 0xff, sizeof(empty));
+        empty_inited = true;
+    }
+
+    CYG_ASSERT(sizeof(empty) < config->block_size,
+               "Eckk! Can't work with such small blocks");
+    CYG_ASSERT((config->block_size % sizeof(empty)) == 0,
+               "Eckk! Can't work with that odd size block");
+    CYG_ASSERT(config->boot_blocks && sizeof(empty) < config->boot_block_size,
+               "Eckk! Can't work with such small blocks");
+    CYG_ASSERT((config->boot_blocks && config->block_size % sizeof(empty)) == 0,
+               "Eckk! Can't work with that odd size block");
+    
+    block_size = flash_block_size(dev, block_base);
+
+    for (i=0; (i * sizeof(empty)) < block_size; i++) {
+        cyg_hal_sys_write(priv->flashfd, empty, sizeof(empty));
+    }
+    return CYG_FLASH_ERR_OK;
+}
+
+static int
+synth_flash_program (struct cyg_flash_dev *dev, 
+                     cyg_flashaddr_t base, 
+                     const void* data, const size_t len)
+{
+    struct cyg_flash_synth_priv *priv = dev->priv;
+    int offset = base;
+    offset -= dev->start;
+    
+    cyg_hal_sys_lseek(priv->flashfd, offset, CYG_HAL_SYS_SEEK_SET);
+    cyg_hal_sys_write(priv->flashfd, data, len);
+  
+    return CYG_FLASH_ERR_OK;
+}
+
+#define QUERY "Linux Synthetic Flash" 
+
+static size_t
+synth_flash_query(struct cyg_flash_dev *dev, void * data, 
+                  const size_t len)
+{
+    memcpy(data,QUERY,sizeof(QUERY));
+    return sizeof(QUERY);
+}
+
+static struct cyg_flash_synth_config config = {
+    CYGNUM_FLASH_SYNTH_V2_BLOCKSIZE,
+    CYGNUM_FLASH_SYNTH_V2_NUMBLOCKS,
+    CYGNUM_FLASH_SYNTH_V2_BOOT_BLOCKSIZE,
+    CYGNUM_FLASH_SYNTH_V2_NUMBOOT_BLOCKS,
+    CYGNUM_FLASH_SYNTH_V2_BOOT_BLOCK_BOTTOM,
+    CYGDAT_FLASH_SYNTH_V2_FILENAME
+};
+
+CYG_FLASH_FUNS(cyg_flash_synth_funs,
+               synth_flash_init,
+               synth_flash_query,
+               synth_flash_erase_block,
+               synth_flash_program,
+               NULL,                 // read
+               synth_flash_hwr_map_error,
+               NULL,                 // lock
+               NULL);                // unlock
+
+CYG_FLASH_DRIVER(cyg_flash_synth_flashdev,
+                 &cyg_flash_synth_funs,
+                 &config,  
+                 CYGMEM_FLASH_SYNTH_V2_BASE,
+                 sizeof(struct cyg_flash_synth_priv)); 
+
+// EOF synth.c