diff options
Diffstat (limited to 'ecos/packages/devs/flash/synthv2/current/src/synth.c')
-rw-r--r-- | ecos/packages/devs/flash/synthv2/current/src/synth.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/ecos/packages/devs/flash/synthv2/current/src/synth.c b/ecos/packages/devs/flash/synthv2/current/src/synth.c new file mode 100644 index 0000000..23003e6 --- /dev/null +++ b/ecos/packages/devs/flash/synthv2/current/src/synth.c @@ -0,0 +1,275 @@ +//========================================================================== +// +// synth.c +// +// Flash programming +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2. +// +// 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): 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> + +#include <cyg/io/flash.h> +#include <cyg/io/flash_dev.h> +#include <cyg/flash/synth.h> + +#ifndef MIN +#define MIN(x,y) ((x)<(y) ? (x) : (y)) +#endif + +static int +synth_flash_init(struct cyg_flash_dev *dev) +{ + struct cyg_flash_synth_priv *priv = + (struct cyg_flash_synth_priv *) dev->priv; + cyg_flashaddr_t base; + int flags = CYG_HAL_SYS_MAP_SHARED; + + priv->flashfd = cyg_hal_sys_open( + priv->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( + priv->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 = priv->block_size * priv->blocks + + priv->boot_block_size * priv->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; + } + } + + 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_mmap( + (void *) dev->start, + priv->blocks * priv->block_size + + priv->boot_block_size * priv->boot_blocks, + CYG_HAL_SYS_PROT_READ, + flags, + priv->flashfd, + 0l); + CYG_ASSERT(base != -1, "mmap of flash file failed!"); + if (base == -1) + return CYG_FLASH_ERR_HWR; + + dev->start = base; + dev->end = base + (priv->blocks * priv->block_size) + + (priv->boot_blocks * priv->boot_block_size) - 1; + if (priv->boot_blocks) { + if (priv->boot_block_bottom) { + priv->block_info[0].block_size = priv->boot_block_size; + priv->block_info[0].blocks = priv->boot_blocks; + priv->block_info[1].block_size = priv->block_size; + priv->block_info[1].blocks = priv->blocks; + } else { + priv->block_info[0].block_size = priv->block_size; + priv->block_info[0].blocks = priv->blocks; + priv->block_info[1].block_size = priv->boot_block_size; + priv->block_info[1].blocks = priv->boot_blocks; + } + dev->num_block_infos = 2; + } else { + priv->block_info[0].block_size = priv->block_size; + priv->block_info[0].blocks = priv->blocks; + dev->num_block_infos = 1; + } + dev->block_info = &priv->block_info[0]; + + return CYG_FLASH_ERR_OK; +} + +// 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; + cyg_flashaddr_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, + cyg_flashaddr_t block_base) +{ + const struct cyg_flash_synth_priv *priv = dev->priv; + cyg_flashaddr_t offset = block_base; + size_t remaining; + int write_size; + + // This helps speed up the erasing + static cyg_uint8 empty[4096]; + static cyg_bool empty_inited; + + 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; + } + + remaining = flash_block_size(dev, block_base); + + while (remaining) { + write_size = MIN(remaining, sizeof(empty)); + cyg_hal_sys_write(priv->flashfd, empty, write_size); + remaining -= write_size; + } + + return CYG_FLASH_ERR_OK; +} + +static int +synth_flash_program (struct cyg_flash_dev *dev, + cyg_flashaddr_t base, + const void* data, size_t len) +{ + const struct cyg_flash_synth_priv *priv = dev->priv; + cyg_flashaddr_t offset = base; + cyg_uint8 *buf = (cyg_uint8 *) data; + + // This helps speed up the programming + static cyg_uint8 tmp[4096]; + + offset -= dev->start; + + while (len > 0) { + int i; + int write_size = MIN(len, sizeof(tmp)); + // Writing to NOR flash only sets bits from 1 to 0, not vice-versa + cyg_hal_sys_lseek(priv->flashfd, offset, CYG_HAL_SYS_SEEK_SET); + cyg_hal_sys_read(priv->flashfd, tmp, write_size); + for (i = 0; i < write_size; i++) + tmp[i] = tmp[i] & buf[i]; + cyg_hal_sys_lseek(priv->flashfd, offset, CYG_HAL_SYS_SEEK_SET); + cyg_hal_sys_write(priv->flashfd, tmp, write_size); + // Process next chunk + buf += write_size; + offset += write_size; + len -= write_size; + } + + return CYG_FLASH_ERR_OK; +} + +#define QUERY "Linux Synthetic Flash" + +static size_t +synth_flash_query(struct cyg_flash_dev *dev, void * data, size_t len) +{ + memcpy(data, QUERY, sizeof(QUERY)); + return sizeof(QUERY); +} + +const CYG_FLASH_FUNS(cyg_flash_synth_funs, + synth_flash_init, + synth_flash_query, + synth_flash_erase_block, + synth_flash_program, + NULL, // read + cyg_flash_devfn_lock_nop, + cyg_flash_devfn_unlock_nop); + +static struct cyg_flash_synth_priv synth_flash_priv = { + .block_size = CYGNUM_FLASH_SYNTH_V2_BLOCKSIZE, + .blocks = CYGNUM_FLASH_SYNTH_V2_NUMBLOCKS, + .boot_block_size = CYGNUM_FLASH_SYNTH_V2_BOOT_BLOCKSIZE, + .boot_blocks = CYGNUM_FLASH_SYNTH_V2_NUMBOOT_BLOCKS, + .boot_block_bottom = CYGNUM_FLASH_SYNTH_V2_BOOT_BLOCK_BOTTOM, + .filename = CYGDAT_FLASH_SYNTH_V2_FILENAME, + .flashfd = -1 +}; + +CYG_FLASH_DRIVER(cyg_flash_synth_flashdev, + &cyg_flash_synth_funs, + 0, // flags + CYGMEM_FLASH_SYNTH_V2_BASE, // Start, if 0 will be updated by init + 0, // end, filled in by init + 0, // number of block_info's, filled in by init + synth_flash_priv.block_info, + &synth_flash_priv); + +// EOF synth.c |