Rearchitecting of some MTD, partition, SMART interfaces, and FLASH drivers to: Better use the byte write capbility when available and to use smaller erase sectors for the erase sector size when available).
This commit is contained in:
parent
2567deb033
commit
1092e4b163
|
@ -546,3 +546,5 @@
|
|||
the SMART block driver and file system (Ken Pettit, 2013-5-1).
|
||||
* apps/examples/mtdpart: Extended to the test. The original test
|
||||
coverage was superficial (2013-5-3).
|
||||
* apps/examples/smart: This is an adaptation of the NXFFS stress
|
||||
test for the SMART file system (Ken Pettit, 2013-5-3).
|
||||
|
|
|
@ -49,6 +49,7 @@ source "$APPSDIR/examples/sendmail/Kconfig"
|
|||
source "$APPSDIR/examples/serloop/Kconfig"
|
||||
source "$APPSDIR/examples/flash_test/Kconfig"
|
||||
source "$APPSDIR/examples/smart_test/Kconfig"
|
||||
source "$APPSDIR/examples/smart/Kconfig"
|
||||
source "$APPSDIR/examples/telnetd/Kconfig"
|
||||
source "$APPSDIR/examples/thttpd/Kconfig"
|
||||
source "$APPSDIR/examples/tiff/Kconfig"
|
||||
|
|
|
@ -222,6 +222,10 @@ ifeq ($(CONFIG_EXAMPLES_SMART_TEST),y)
|
|||
CONFIGURED_APPS += examples/smart_test
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_EXAMPLES_SMART),y)
|
||||
CONFIGURED_APPS += examples/smart
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_EXAMPLES_TELNETD),y)
|
||||
CONFIGURED_APPS += examples/telnetd
|
||||
endif
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#
|
||||
############################################################################
|
||||
|
||||
-include $(TOPDIR)/.config # Current configuration
|
||||
-include $(TOPDIR)/.config # Current configuration
|
||||
|
||||
# Sub-directories
|
||||
|
||||
|
@ -42,8 +42,8 @@ SUBDIRS += flash_test ftpc ftpd hello helloxx hidkbd igmp json keypadtest
|
|||
SUBDIRS += lcdrw mm modbus mount mtdpart nettest nsh null nx nxconsole nxffs
|
||||
SUBDIRS += nxflat nxhello nximage nxlines nxtext ostest pashello pipe poll
|
||||
SUBDIRS += posix_spawn pwm qencoder relays rgmp romfs sendmail serloop
|
||||
SUBDIRS += smart_test telnetd thttpd tiff touchscreen udp uip usbserial
|
||||
SUBDIRS += usbstorage usbterm watchdog wget wgetjson xmlrpc
|
||||
SUBDIRS += smart smart_test telnetd thttpd tiff touchscreen udp uip
|
||||
SUBDIRS += usbserial usbstorage usbterm watchdog wget wgetjson xmlrpc
|
||||
|
||||
# Sub-directories that might need context setup. Directories may need
|
||||
# context setup for a variety of reasons, but the most common is because
|
||||
|
|
|
@ -1463,6 +1463,34 @@ examples/serloop
|
|||
Use C buffered I/O (getchar/putchar) vs. raw console I/O
|
||||
(read/read).
|
||||
|
||||
examples/smart
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
This is a test of the SMART file systemt that derives from
|
||||
examples/nxffs.
|
||||
|
||||
* CONFIG_EXAMPLES_SMART: -Enable the SMART file system example
|
||||
* CONFIG_EXAMPLES_SMART_ARCHINIT: The default is to use the RAM MTD
|
||||
device at drivers/mtd/rammtd.c. But an architecture-specific MTD
|
||||
driver can be used instead by defining CONFIG_EXAMPLES_SMART_ARCHINIT. In
|
||||
this case, the initialization logic will call smart_archinitialize()
|
||||
to obtain the MTD driver instance.
|
||||
* CONFIG_EXAMPLES_SMART_NEBLOCKS: When CONFIG_EXAMPLES_SMART_ARCHINIT is not
|
||||
defined, this test will use the RAM MTD device at drivers/mtd/rammtd.c
|
||||
to simulate FLASH. In this case, this value must be provided to give
|
||||
the nubmer of erase blocks in MTD RAM device. The size of the allocated
|
||||
RAM drive will be: CONFIG_RAMMTD_ERASESIZE * CONFIG_EXAMPLES_SMART_NEBLOCKS
|
||||
* CONFIG_EXAMPLES_SMART_MAXNAME: Determines the maximum size of names used
|
||||
in the filesystem
|
||||
* CONFIG_EXAMPLES_SMART_MAXFILE: Determines the maximum size of a file
|
||||
* CONFIG_EXAMPLES_SMART_MAXIO: Max I/O, default 347.
|
||||
* CONFIG_EXAMPLES_SMART_MAXOPEN: Max open files.
|
||||
* CONFIG_EXAMPLES_SMART_MOUNTPT: SMART mountpoint
|
||||
* CONFIG_EXAMPLES_SMART_NLOOPS: Number of test loops. default 100
|
||||
* CONFIG_EXAMPLES_SMART_VERBOSE: Verbose output
|
||||
|
||||
endif
|
||||
|
||||
examples/smart_test
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -6,8 +6,12 @@
|
|||
config EXAMPLES_MTDPART
|
||||
bool "MTD partition test"
|
||||
default n
|
||||
depends on MTD_PARTITION && !NUTTX_KERNEL
|
||||
---help---
|
||||
Enable the MTD partition test example
|
||||
Enable the MTD partition test example.
|
||||
|
||||
NOTE: This example uses some internal NuttX interfaces and, hence,
|
||||
is not available in the kernel build.
|
||||
|
||||
if EXAMPLES_MTDPART
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
Make.dep
|
||||
.depend
|
||||
.built
|
||||
*.swp
|
||||
*.asm
|
||||
*.rel
|
||||
*.lst
|
||||
*.sym
|
||||
*.adb
|
||||
*.lib
|
||||
*.src
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see misc/tools/kconfig-language.txt.
|
||||
#
|
||||
|
||||
config EXAMPLES_SMART
|
||||
bool "SMART file system example"
|
||||
default n
|
||||
---help---
|
||||
Enable the SMART file system example
|
||||
|
||||
if EXAMPLES_SMART
|
||||
|
||||
config EXAMPLES_SMART_ARCHINIT
|
||||
bool "Architecture-specific initialization"
|
||||
default n
|
||||
---help---
|
||||
The default is to use the RAM MTD device at drivers/mtd/rammtd.c.
|
||||
But an architecture-specific MTD driver can be used instead by
|
||||
defining EXAMPLES_SMART_ARCHINIT. In this case, the
|
||||
initialization logic will call smart_archinitialize() to obtain
|
||||
the MTD driver instance.
|
||||
|
||||
config EXAMPLES_SMART_NEBLOCKS
|
||||
int "Number of erase blocks (simulated)"
|
||||
default 32
|
||||
depends on !EXAMPLES_SMART_ARCHINIT
|
||||
---help---
|
||||
When EXAMPLES_SMART_ARCHINIT is not defined, this test will use
|
||||
the RAM MTD device at drivers/mtd/rammtd.c to simulate FLASH. In
|
||||
this case, this value must be provided to give the nubmer of erase
|
||||
blocks in MTD RAM device.
|
||||
|
||||
The size of the allocated RAM drive will be:
|
||||
|
||||
RAMMTD_ERASESIZE * EXAMPLES_SMART_NEBLOCKS
|
||||
|
||||
config EXAMPLES_SMART_MAXNAME
|
||||
int "Max name size"
|
||||
default 32
|
||||
range 1 255
|
||||
---help---
|
||||
Determines the maximum size of names used in the filesystem
|
||||
|
||||
config EXAMPLES_SMART_MAXFILE
|
||||
int "Max file size"
|
||||
default 8192
|
||||
---help---
|
||||
Determines the maximum size of a file
|
||||
|
||||
config EXAMPLES_SMART_MAXIO
|
||||
int "Max I/O"
|
||||
default 347
|
||||
|
||||
config EXAMPLES_SMART_MAXOPEN
|
||||
int "Max open files"
|
||||
default 512
|
||||
|
||||
config EXAMPLES_SMART_MOUNTPT
|
||||
string "SMART mountpoint"
|
||||
default "/mnt/nxffs"
|
||||
|
||||
config EXAMPLES_SMART_NLOOPS
|
||||
int "Number of test loops"
|
||||
default 100
|
||||
|
||||
config EXAMPLES_SMART_VERBOSE
|
||||
bool "Verbose output"
|
||||
default n
|
||||
|
||||
endif
|
|
@ -0,0 +1,96 @@
|
|||
############################################################################
|
||||
# apps/examples/smart/Makefile
|
||||
#
|
||||
# Copyright (C) 2011-2013 Gregory Nutt. All rights reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name NuttX nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
-include $(TOPDIR)/.config
|
||||
-include $(TOPDIR)/Make.defs
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# SMART file system stress test
|
||||
|
||||
ASRCS =
|
||||
CSRCS = smart_main.c
|
||||
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
|
||||
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
BIN = ..\..\libapps$(LIBEXT)
|
||||
else
|
||||
ifeq ($(WINTOOL),y)
|
||||
BIN = ..\\..\\libapps$(LIBEXT)
|
||||
else
|
||||
BIN = ../../libapps$(LIBEXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
ROOTDEPPATH = --dep-path .
|
||||
|
||||
# Common build
|
||||
|
||||
VPATH =
|
||||
|
||||
all: .built
|
||||
.PHONY: clean depend distclean
|
||||
|
||||
$(AOBJS): %$(OBJEXT): %.S
|
||||
$(call ASSEMBLE, $<, $@)
|
||||
|
||||
$(COBJS): %$(OBJEXT): %.c
|
||||
$(call COMPILE, $<, $@)
|
||||
|
||||
.built: $(OBJS)
|
||||
$(call ARCHIVE, $(BIN), $(OBJS))
|
||||
@touch .built
|
||||
|
||||
context:
|
||||
|
||||
.depend: Makefile $(SRCS)
|
||||
@$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
|
||||
@touch $@
|
||||
|
||||
depend: .depend
|
||||
|
||||
clean:
|
||||
$(call DELFILE, .built)
|
||||
$(call CLEAN)
|
||||
|
||||
distclean: clean
|
||||
$(call DELFILE, Make.dep)
|
||||
$(call DELFILE, .depend)
|
||||
|
||||
-include Make.dep
|
|
@ -0,0 +1,954 @@
|
|||
/****************************************************************************
|
||||
* examples/smart/smart_main.c
|
||||
*
|
||||
* Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <crc32.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mtd.h>
|
||||
#include <nuttx/smart.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
#include <nuttx/fs/mksmartfs.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************/
|
||||
/* The default is to use the RAM MTD device at drivers/mtd/rammtd.c. But
|
||||
* an architecture-specific MTD driver can be used instead by defining
|
||||
* CONFIG_EXAMPLES_SMART_ARCHINIT. In this case, the initialization logic
|
||||
* will call smart_archinitialize() to obtain the MTD driver instance.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_ARCHINIT
|
||||
|
||||
/* This must exactly match the default configuration in drivers/mtd/rammtd.c */
|
||||
|
||||
# ifndef CONFIG_RAMMTD_ERASESIZE
|
||||
# define CONFIG_RAMMTD_ERASESIZE 4096
|
||||
# endif
|
||||
|
||||
# ifndef CONFIG_EXAMPLES_SMART_NEBLOCKS
|
||||
# define CONFIG_EXAMPLES_SMART_NEBLOCKS (256)
|
||||
# endif
|
||||
|
||||
# define EXAMPLES_SMART_BUFSIZE \
|
||||
(CONFIG_RAMMTD_ERASESIZE * CONFIG_EXAMPLES_SMART_NEBLOCKS)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_MAXNAME
|
||||
# define CONFIG_EXAMPLES_SMART_MAXNAME 128
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLES_SMART_MAXNAME > 255
|
||||
# undef CONFIG_EXAMPLES_SMART_MAXNAME
|
||||
# define CONFIG_EXAMPLES_SMART_MAXNAME 255
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_MAXFILE
|
||||
# define CONFIG_EXAMPLES_SMART_MAXFILE 8192
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_MAXIO
|
||||
# define CONFIG_EXAMPLES_SMART_MAXIO 347
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_MAXOPEN
|
||||
# define CONFIG_EXAMPLES_SMART_MAXOPEN 512
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_MOUNTPT
|
||||
# define CONFIG_EXAMPLES_SMART_MOUNTPT "/mnt/smart"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_NLOOPS
|
||||
# define CONFIG_EXAMPLES_SMART_NLOOPS 100
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_VERBOSE
|
||||
# define CONFIG_EXAMPLES_SMART_VERBOSE 0
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_FS)
|
||||
# define message syslog
|
||||
# define msgflush()
|
||||
#else
|
||||
# define message printf
|
||||
# define msgflush() fflush(stdout);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct smart_filedesc_s
|
||||
{
|
||||
FAR char *name;
|
||||
bool deleted;
|
||||
size_t len;
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
/* Pre-allocated simulated flash */
|
||||
|
||||
#ifndef CONFIG_EXAMPLES_SMART_ARCHINIT
|
||||
static uint8_t g_simflash[EXAMPLES_SMART_BUFSIZE];
|
||||
#endif
|
||||
|
||||
static uint8_t g_fileimage[CONFIG_EXAMPLES_SMART_MAXFILE];
|
||||
static struct smart_filedesc_s g_files[CONFIG_EXAMPLES_SMART_MAXOPEN];
|
||||
static const char g_mountdir[] = CONFIG_EXAMPLES_SMART_MOUNTPT "/";
|
||||
static int g_nfiles;
|
||||
static int g_ndeleted;
|
||||
|
||||
static struct mallinfo g_mmbefore;
|
||||
static struct mallinfo g_mmprevious;
|
||||
static struct mallinfo g_mmafter;
|
||||
|
||||
/****************************************************************************
|
||||
* External Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_EXAMPLES_SMART_ARCHINIT
|
||||
extern FAR struct mtd_dev_s *smart_archinitialize(void);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_memusage
|
||||
****************************************************************************/
|
||||
|
||||
static void smart_showmemusage(struct mallinfo *mmbefore,
|
||||
struct mallinfo *mmafter)
|
||||
{
|
||||
message("VARIABLE BEFORE AFTER\n");
|
||||
message("======== ======== ========\n");
|
||||
message("arena %8x %8x\n", mmbefore->arena, mmafter->arena);
|
||||
message("ordblks %8d %8d\n", mmbefore->ordblks, mmafter->ordblks);
|
||||
message("mxordblk %8x %8x\n", mmbefore->mxordblk, mmafter->mxordblk);
|
||||
message("uordblks %8x %8x\n", mmbefore->uordblks, mmafter->uordblks);
|
||||
message("fordblks %8x %8x\n", mmbefore->fordblks, mmafter->fordblks);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_loopmemusage
|
||||
****************************************************************************/
|
||||
|
||||
static void smart_loopmemusage(void)
|
||||
{
|
||||
/* Get the current memory usage */
|
||||
|
||||
#ifdef CONFIG_CAN_PASS_STRUCTS
|
||||
g_mmafter = mallinfo();
|
||||
#else
|
||||
(void)mallinfo(&g_mmafter);
|
||||
#endif
|
||||
|
||||
/* Show the change from the previous loop */
|
||||
|
||||
message("\nEnd of loop memory usage:\n");
|
||||
smart_showmemusage(&g_mmprevious, &g_mmafter);
|
||||
|
||||
/* Set up for the next test */
|
||||
|
||||
#ifdef CONFIG_CAN_PASS_STRUCTS
|
||||
g_mmprevious = g_mmafter;
|
||||
#else
|
||||
memcpy(&g_mmprevious, &g_mmafter, sizeof(struct mallinfo));
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_endmemusage
|
||||
****************************************************************************/
|
||||
|
||||
static void smart_endmemusage(void)
|
||||
{
|
||||
#ifdef CONFIG_CAN_PASS_STRUCTS
|
||||
g_mmafter = mallinfo();
|
||||
#else
|
||||
(void)mallinfo(&g_mmafter);
|
||||
#endif
|
||||
message("\nFinal memory usage:\n");
|
||||
smart_showmemusage(&g_mmbefore, &g_mmafter);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_randchar
|
||||
****************************************************************************/
|
||||
|
||||
static inline char smart_randchar(void)
|
||||
{
|
||||
int value = rand() % 63;
|
||||
if (value == 0)
|
||||
{
|
||||
return '0';
|
||||
}
|
||||
else if (value <= 10)
|
||||
{
|
||||
return value + '0' - 1;
|
||||
}
|
||||
else if (value <= 36)
|
||||
{
|
||||
return value + 'a' - 11;
|
||||
}
|
||||
else /* if (value <= 62) */
|
||||
{
|
||||
return value + 'A' - 37;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_randname
|
||||
****************************************************************************/
|
||||
|
||||
static inline void smart_randname(FAR struct smart_filedesc_s *file)
|
||||
{
|
||||
int dirlen;
|
||||
int maxname;
|
||||
int namelen;
|
||||
int alloclen;
|
||||
int i;
|
||||
|
||||
dirlen = strlen(g_mountdir);
|
||||
maxname = CONFIG_EXAMPLES_SMART_MAXNAME - dirlen;
|
||||
namelen = (rand() % maxname) + 1;
|
||||
alloclen = namelen + dirlen;
|
||||
|
||||
file->name = (FAR char*)malloc(alloclen + 1);
|
||||
if (!file->name)
|
||||
{
|
||||
message("ERROR: Failed to allocate name, length=%d\n", namelen);
|
||||
msgflush();
|
||||
exit(5);
|
||||
}
|
||||
|
||||
memcpy(file->name, g_mountdir, dirlen);
|
||||
for (i = dirlen; i < alloclen; i++)
|
||||
{
|
||||
file->name[i] = smart_randchar();
|
||||
}
|
||||
|
||||
file->name[alloclen] = '\0';
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_randfile
|
||||
****************************************************************************/
|
||||
|
||||
static inline void smart_randfile(FAR struct smart_filedesc_s *file)
|
||||
{
|
||||
int i;
|
||||
|
||||
file->len = (rand() % CONFIG_EXAMPLES_SMART_MAXFILE) + 1;
|
||||
for (i = 0; i < file->len; i++)
|
||||
{
|
||||
g_fileimage[i] = smart_randchar();
|
||||
}
|
||||
|
||||
file->crc = crc32(g_fileimage, file->len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_freefile
|
||||
****************************************************************************/
|
||||
|
||||
static void smart_freefile(FAR struct smart_filedesc_s *file)
|
||||
{
|
||||
if (file->name)
|
||||
{
|
||||
free(file->name);
|
||||
}
|
||||
|
||||
memset(file, 0, sizeof(struct smart_filedesc_s));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_wrfile
|
||||
****************************************************************************/
|
||||
|
||||
static inline int smart_wrfile(FAR struct smart_filedesc_s *file)
|
||||
{
|
||||
size_t offset;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
/* Create a random file */
|
||||
|
||||
smart_randname(file);
|
||||
smart_randfile(file);
|
||||
fd = open(file->name, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||
if (fd < 0)
|
||||
{
|
||||
/* If it failed because there is no space on the device, then don't
|
||||
* complain.
|
||||
*/
|
||||
|
||||
if (errno != ENOSPC)
|
||||
{
|
||||
message("ERROR: Failed to open file for writing: %d\n", errno);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
}
|
||||
|
||||
smart_freefile(file);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Write a random amount of data to the file */
|
||||
|
||||
for (offset = 0; offset < file->len; )
|
||||
{
|
||||
size_t maxio = (rand() % CONFIG_EXAMPLES_SMART_MAXIO) + 1;
|
||||
size_t nbytestowrite = file->len - offset;
|
||||
ssize_t nbyteswritten;
|
||||
|
||||
if (nbytestowrite > maxio)
|
||||
{
|
||||
nbytestowrite = maxio;
|
||||
}
|
||||
|
||||
nbyteswritten = write(fd, &g_fileimage[offset], nbytestowrite);
|
||||
if (nbyteswritten < 0)
|
||||
{
|
||||
int err = errno;
|
||||
|
||||
/* If the write failed because there is no space on the device,
|
||||
* then don't complain.
|
||||
*/
|
||||
|
||||
if (err != ENOSPC)
|
||||
{
|
||||
message("ERROR: Failed to write file: %d\n", err);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" Write offset: %d\n", offset);
|
||||
message(" Write size: %d\n", nbytestowrite);
|
||||
ret = ERROR;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* Remove any garbage file that might have been left behind */
|
||||
|
||||
ret = unlink(file->name);
|
||||
if (ret < 0)
|
||||
{
|
||||
message(" Failed to remove partial file\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message(" Successfully removed partial file\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
smart_freefile(file);
|
||||
return ERROR;
|
||||
}
|
||||
else if (nbyteswritten != nbytestowrite)
|
||||
{
|
||||
message("ERROR: Partial write:\n");
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" Write offset: %d\n", offset);
|
||||
message(" Write size: %d\n", nbytestowrite);
|
||||
message(" Written: %d\n", nbyteswritten);
|
||||
}
|
||||
|
||||
offset += nbyteswritten;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_fillfs
|
||||
****************************************************************************/
|
||||
|
||||
static int smart_fillfs(void)
|
||||
{
|
||||
FAR struct smart_filedesc_s *file;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Create a file for each unused file structure */
|
||||
|
||||
for (i = 0; i < CONFIG_EXAMPLES_SMART_MAXOPEN; i++)
|
||||
{
|
||||
file = &g_files[i];
|
||||
if (file->name == NULL)
|
||||
{
|
||||
ret = smart_wrfile(file);
|
||||
if (ret < 0)
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message("ERROR: Failed to write file %d\n", i);
|
||||
#endif
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message(" Created file %s\n", file->name);
|
||||
#endif
|
||||
g_nfiles++;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_rdblock
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t smart_rdblock(int fd, FAR struct smart_filedesc_s *file,
|
||||
size_t offset, size_t len)
|
||||
{
|
||||
size_t maxio = (rand() % CONFIG_EXAMPLES_SMART_MAXIO) + 1;
|
||||
ssize_t nbytesread;
|
||||
|
||||
if (len > maxio)
|
||||
{
|
||||
len = maxio;
|
||||
}
|
||||
|
||||
nbytesread = read(fd, &g_fileimage[offset], len);
|
||||
if (nbytesread < 0)
|
||||
{
|
||||
message("ERROR: Failed to read file: %d\n", errno);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" Read offset: %d\n", offset);
|
||||
message(" Read size: %d\n", len);
|
||||
return ERROR;
|
||||
}
|
||||
else if (nbytesread == 0)
|
||||
{
|
||||
#if 0 /* No... we do this on purpose sometimes */
|
||||
message("ERROR: Unexpected end-of-file:\n");
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" Read offset: %d\n", offset);
|
||||
message(" Read size: %d\n", len);
|
||||
#endif
|
||||
return ERROR;
|
||||
}
|
||||
else if (nbytesread != len)
|
||||
{
|
||||
message("ERROR: Partial read:\n");
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" Read offset: %d\n", offset);
|
||||
message(" Read size: %d\n", len);
|
||||
message(" Bytes read: %d\n", nbytesread);
|
||||
}
|
||||
|
||||
return nbytesread;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_rdfile
|
||||
****************************************************************************/
|
||||
|
||||
static inline int smart_rdfile(FAR struct smart_filedesc_s *file)
|
||||
{
|
||||
size_t ntotalread;
|
||||
ssize_t nbytesread;
|
||||
uint32_t crc;
|
||||
int fd;
|
||||
|
||||
/* Open the file for reading */
|
||||
|
||||
fd = open(file->name, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!file->deleted)
|
||||
{
|
||||
message("ERROR: Failed to open file for reading: %d\n", errno);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
}
|
||||
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Read all of the data info the fileimage buffer using random read sizes */
|
||||
|
||||
for (ntotalread = 0; ntotalread < file->len; )
|
||||
{
|
||||
nbytesread = smart_rdblock(fd, file, ntotalread, file->len - ntotalread);
|
||||
if (nbytesread < 0)
|
||||
{
|
||||
close(fd);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ntotalread += nbytesread;
|
||||
}
|
||||
|
||||
/* Verify the file image CRC */
|
||||
|
||||
crc = crc32(g_fileimage, file->len);
|
||||
if (crc != file->crc)
|
||||
{
|
||||
message("ERROR: Bad CRC: %d vs %d\n", crc, file->crc);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
close(fd);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Try reading past the end of the file */
|
||||
|
||||
nbytesread = smart_rdblock(fd, file, ntotalread, 1024) ;
|
||||
if (nbytesread > 0)
|
||||
{
|
||||
message("ERROR: Read past the end of file\n");
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" Bytes read: %d\n", nbytesread);
|
||||
close(fd);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_verifyfs
|
||||
****************************************************************************/
|
||||
|
||||
static int smart_verifyfs(void)
|
||||
{
|
||||
FAR struct smart_filedesc_s *file;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Create a file for each unused file structure */
|
||||
|
||||
for (i = 0; i < CONFIG_EXAMPLES_SMART_MAXOPEN; i++)
|
||||
{
|
||||
file = &g_files[i];
|
||||
if (file->name != NULL)
|
||||
{
|
||||
ret = smart_rdfile(file);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (file->deleted)
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message("Deleted file %d OK\n", i);
|
||||
#endif
|
||||
smart_freefile(file);
|
||||
g_ndeleted--;
|
||||
g_nfiles--;
|
||||
}
|
||||
else
|
||||
{
|
||||
message("ERROR: Failed to read a file: %d\n", i);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file->deleted)
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message("Succesffully read a deleted file\n");
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
#endif
|
||||
smart_freefile(file);
|
||||
g_ndeleted--;
|
||||
g_nfiles--;
|
||||
return ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message(" Verifed file %s\n", file->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_delfiles
|
||||
****************************************************************************/
|
||||
|
||||
static int smart_delfiles(void)
|
||||
{
|
||||
FAR struct smart_filedesc_s *file;
|
||||
int ndel;
|
||||
int ret;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
/* Are there any files to be deleted? */
|
||||
|
||||
int nfiles = g_nfiles - g_ndeleted;
|
||||
if (nfiles < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Yes... How many files should we delete? */
|
||||
|
||||
ndel = (rand() % nfiles) + 1;
|
||||
|
||||
/* Now pick which files to delete */
|
||||
|
||||
for (i = 0; i < ndel; i++)
|
||||
{
|
||||
/* Guess a file index */
|
||||
|
||||
int ndx = (rand() % (g_nfiles - g_ndeleted));
|
||||
|
||||
/* And delete the next undeleted file after that random index */
|
||||
|
||||
for (j = ndx + 1; j != ndx;)
|
||||
{
|
||||
file = &g_files[j];
|
||||
if (file->name && !file->deleted)
|
||||
{
|
||||
ret = unlink(file->name);
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: Unlink %d failed: %d\n", i+1, errno);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" File index: %d\n", j);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message(" Deleted file %s\n", file->name);
|
||||
#endif
|
||||
file->deleted = true;
|
||||
g_ndeleted++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the index and test for wrap-around */
|
||||
|
||||
if (++j >= CONFIG_EXAMPLES_SMART_MAXOPEN)
|
||||
{
|
||||
j = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_delallfiles
|
||||
****************************************************************************/
|
||||
|
||||
static int smart_delallfiles(void)
|
||||
{
|
||||
FAR struct smart_filedesc_s *file;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_EXAMPLES_SMART_MAXOPEN; i++)
|
||||
{
|
||||
file = &g_files[i];
|
||||
if (file->name)
|
||||
{
|
||||
ret = unlink(file->name);
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: Unlink %d failed: %d\n", i+1, errno);
|
||||
message(" File name: %s\n", file->name);
|
||||
message(" File size: %d\n", file->len);
|
||||
message(" File index: %d\n", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message(" Deleted file %s\n", file->name);
|
||||
#endif
|
||||
smart_freefile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_nfiles = 0;
|
||||
g_ndeleted = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_directory
|
||||
****************************************************************************/
|
||||
|
||||
static int smart_directory(void)
|
||||
{
|
||||
DIR *dirp;
|
||||
FAR struct dirent *entryp;
|
||||
int number;
|
||||
|
||||
/* Open the directory */
|
||||
|
||||
dirp = opendir(CONFIG_EXAMPLES_SMART_MOUNTPT);
|
||||
|
||||
if (!dirp)
|
||||
{
|
||||
/* Failed to open the directory */
|
||||
|
||||
message("ERROR: Failed to open directory '%s': %d\n",
|
||||
CONFIG_EXAMPLES_SMART_MOUNTPT, errno);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Read each directory entry */
|
||||
|
||||
message("Directory:\n");
|
||||
number = 1;
|
||||
do
|
||||
{
|
||||
entryp = readdir(dirp);
|
||||
if (entryp)
|
||||
{
|
||||
message("%2d. Type[%d]: %s Name: %s\n",
|
||||
number, entryp->d_type,
|
||||
entryp->d_type == DTYPE_FILE ? "File " : "Error",
|
||||
entryp->d_name);
|
||||
}
|
||||
|
||||
number++;
|
||||
}
|
||||
while (entryp != NULL);
|
||||
|
||||
closedir(dirp);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_main
|
||||
****************************************************************************/
|
||||
|
||||
int smart_main(int argc, char *argv[])
|
||||
{
|
||||
FAR struct mtd_dev_s *mtd;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* Seed the random number generated */
|
||||
|
||||
srand(0x93846);
|
||||
|
||||
/* Create and initialize a RAM MTD device instance */
|
||||
|
||||
#ifdef CONFIG_EXAMPLES_SMART_ARCHINIT
|
||||
mtd = smart_archinitialize();
|
||||
#else
|
||||
mtd = rammtd_initialize(g_simflash, EXAMPLES_SMART_BUFSIZE);
|
||||
#endif
|
||||
if (!mtd)
|
||||
{
|
||||
message("ERROR: Failed to create RAM MTD instance\n");
|
||||
msgflush();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Initialize to provide SMART on an MTD interface */
|
||||
|
||||
MTD_IOCTL(mtd, MTDIOC_BULKERASE, 0);
|
||||
ret = smart_initialize(1, mtd);
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: SMART initialization failed: %d\n", -ret);
|
||||
msgflush();
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* Creaet a SMARTFS filesystem */
|
||||
|
||||
ret = mksmartfs("/dev/smart1");
|
||||
|
||||
/* Mount the file system */
|
||||
|
||||
ret = mount("/dev/smart1", CONFIG_EXAMPLES_SMART_MOUNTPT, "smartfs", 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: Failed to mount the SMART volume: %d\n", errno);
|
||||
msgflush();
|
||||
exit(3);
|
||||
}
|
||||
|
||||
/* Set up memory monitoring */
|
||||
|
||||
#ifdef CONFIG_CAN_PASS_STRUCTS
|
||||
g_mmbefore = mallinfo();
|
||||
g_mmprevious = g_mmbefore;
|
||||
#else
|
||||
(void)mallinfo(&g_mmbefore);
|
||||
memcpy(&g_mmprevious, &g_mmbefore, sizeof(struct mallinfo));
|
||||
#endif
|
||||
|
||||
/* Loop a few times ... file the file system with some random, files,
|
||||
* delete some files randomly, fill the file system with more random file,
|
||||
* delete, etc. This beats the FLASH very hard!
|
||||
*/
|
||||
|
||||
#if CONFIG_EXAMPLES_SMART_NLOOPS == 0
|
||||
for (i = 0; ; i++)
|
||||
#else
|
||||
for (i = 1; i <= CONFIG_EXAMPLES_SMART_NLOOPS; i++)
|
||||
#endif
|
||||
{
|
||||
/* Write a files to the SMART file system until either (1) all of the
|
||||
* open file structures are utilized or until (2) SMART reports an error
|
||||
* (hopefully that the file system is full)
|
||||
*/
|
||||
|
||||
message("\n=== FILLING %d =============================\n", i);
|
||||
ret = smart_fillfs();
|
||||
message("Filled file system\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
|
||||
/* Directory listing */
|
||||
|
||||
smart_directory();
|
||||
|
||||
/* Verify all files written to FLASH */
|
||||
|
||||
ret = smart_verifyfs();
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: Failed to verify files\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message("Verified!\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Delete some files */
|
||||
|
||||
message("\n=== DELETING %d ============================\n", i);
|
||||
ret = smart_delfiles();
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: Failed to delete files\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
}
|
||||
else
|
||||
{
|
||||
message("Deleted some files\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
}
|
||||
|
||||
/* Directory listing */
|
||||
|
||||
smart_directory();
|
||||
|
||||
/* Verify all files written to FLASH */
|
||||
|
||||
ret = smart_verifyfs();
|
||||
if (ret < 0)
|
||||
{
|
||||
message("ERROR: Failed to verify files\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CONFIG_EXAMPLES_SMART_VERBOSE != 0
|
||||
message("Verified!\n");
|
||||
message(" Number of files: %d\n", g_nfiles);
|
||||
message(" Number deleted: %d\n", g_ndeleted);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Show memory usage */
|
||||
|
||||
smart_loopmemusage();
|
||||
msgflush();
|
||||
}
|
||||
|
||||
/* Delete all files then show memory usage again */
|
||||
|
||||
smart_delallfiles();
|
||||
smart_endmemusage();
|
||||
msgflush();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
****************************************************************************/
|
||||
|
||||
#define SMART_TEST_LINE_COUNT 2000
|
||||
#define SMART_TEST_SEEK_WRITE_COUNT 12000
|
||||
#define SMART_TEST_SEEK_WRITE_COUNT 2000
|
||||
|
||||
/****************************************************************************
|
||||
* Private data
|
||||
|
|
|
@ -4651,7 +4651,7 @@
|
|||
* configs/sim/mtdpart: A new configuration to test MTD
|
||||
partitions (2013-4-30).
|
||||
* configs/sim/mkroe-stm32f4: Support for the MikroElektronika
|
||||
Mikromedia for STM32F4 development board (from Ken Petit, 2013-4-30).
|
||||
Mikromedia for STM32F4 development board (from Ken Pettit, 2013-4-30).
|
||||
* fs/smartfs: Add Ken Pettits SMART FS (2013-4-30).
|
||||
* include/nuttx/mtd.h and most MTD drivers: Add support for
|
||||
(optional) method to perform byte oriented writes if so configured
|
||||
|
@ -4663,3 +4663,9 @@
|
|||
(option) byte write method (2013-5-3).
|
||||
* arch/arm/src/kl: Repartitioning of definitions in headef files
|
||||
from Alan Carvalho de Assis (2013-5-3).
|
||||
* drivers/mtd/smart.c, fs/smart, and other files: SMART file system
|
||||
now makes use of the MTD byte write capabilities when present (from
|
||||
Ken Pettit, 2013-5-3).
|
||||
* drivers/mtd/m25px.c: Some rearchitecting to use the byte write
|
||||
capability (when possible) and to use 4KB sectors for the erase block
|
||||
size when the part supports it (Ken Pettit, 2013-5-3).
|
||||
|
|
|
@ -2552,6 +2552,19 @@ nsh>
|
|||
<p>
|
||||
<b>STMicro STM32F4-Discovery (STM32 F4 family)</b>.
|
||||
This port uses the STMicro STM32F4-Discovery board featuring the STM32F407VGT6 MCU.
|
||||
The STM32F407VGT6 is a 168MHz Cortex-M4 operation with 1Mbit Flash memory and 128kbytes.
|
||||
The board features:
|
||||
</p>
|
||||
<ul>
|
||||
<li>On-board ST-LINK/V2 for programming and debugging,</li>
|
||||
<li>LIS302DL, ST MEMS motion sensor, 3-axis digital output accelerometer,</li>
|
||||
<li>MP45DT02, ST MEMS audio sensor, omni-directional digital microphone,</li>
|
||||
<li>CS43L22, audio DAC with integrated class D speaker driver,</li>
|
||||
<li>Eight LEDs and two push-buttons,</li>
|
||||
<li>USB OTG FS with micro-AB connector, and</li>
|
||||
<li>Easy access to most MCU pins.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Refer to the <a href="http://www.st.com/internet/evalboard/product/252419.jsp">STMicro web site</a> for further information about this board.
|
||||
</p>
|
||||
<ul>
|
||||
|
@ -2567,6 +2580,38 @@ nsh>
|
|||
<td><br></td>
|
||||
<td><hr></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><br></td>
|
||||
<td>
|
||||
<p>
|
||||
<b>MikroElektronika Mikromedia for STM32F4</b>.
|
||||
This is another board supported by NuttX that uses the same STM32F407VGT6 MCU as does the STM32F4-Discovery board.
|
||||
This board, however, has very different on-board peripherals than does the STM32F4-Discovery:
|
||||
</p>
|
||||
<ul>
|
||||
<li>TFT display with touch panel,</li>
|
||||
<li>VS1053 stereo audio codec with headphone jack,</li>
|
||||
<li>SD card slot,</li>
|
||||
<li>Serial FLASH memory,</li>
|
||||
<li>USB OTG FS with micro-AB connector, and</li>
|
||||
<li>Battery connect and batter charger circuit.</li>
|
||||
</ul>
|
||||
<p>
|
||||
See the <a href="http://www.mikroe.com/mikromedia/stm32-m4/">Mikroelektronika website<a> for more information about this board.
|
||||
</p>
|
||||
<ul>
|
||||
<p>
|
||||
<b>STATUS:</b>
|
||||
The basic port for the Mikromedia STM32 M4 was contributed by Ken Petit and was first released in NuttX-6.128.
|
||||
All drivers for the STM32 F4 family may be used with this board as well.
|
||||
</p>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><br></td>
|
||||
<td><hr></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><br></td>
|
||||
<td>
|
||||
|
|
|
@ -5,53 +5,94 @@
|
|||
|
||||
if ARCH_BOARD_MIKROE_STM32F4
|
||||
|
||||
config PM_BUTTONS
|
||||
bool "PM Button support"
|
||||
config MIKROE_FLASH
|
||||
bool "MTD driver for onboard 1M FLASH"
|
||||
default n
|
||||
depends on PM && ARCH_IRQBUTTONS
|
||||
select MTD
|
||||
select MTD_M25P
|
||||
select MTD_SMART
|
||||
select FS_SMARTFS
|
||||
select STM32_SPI3
|
||||
select MTD_BYTE_WRITE
|
||||
---help---
|
||||
Enable PM button EXTI interrupts to support PM testing
|
||||
Configures an MTD device for use with the onboard flash
|
||||
|
||||
config PM_BUTTON_ACTIVITY
|
||||
int "Button PM activity weight"
|
||||
default 10
|
||||
depends on PM_BUTTONS
|
||||
config MIKROE_FLASH_MINOR
|
||||
int "Minor number for the FLASH /dev/smart entry"
|
||||
default 0
|
||||
depends on MIKROE_FLASH
|
||||
---help---
|
||||
The activity weight to report to the power management subsystem when a button is pressed.
|
||||
Sets the minor number for the FLASH MTD /dev entry
|
||||
|
||||
config MIKROE_FLASH_PART
|
||||
bool "Enable partition support on FLASH"
|
||||
default n
|
||||
depends on MIKROE_FLASH
|
||||
---help---
|
||||
Enables creation of partitions on the FLASH
|
||||
|
||||
config MIKROE_FLASH_PART_LIST
|
||||
string "Flash partition size list"
|
||||
default "256,768"
|
||||
depends on MIKROE_FLASH_PART
|
||||
---help---
|
||||
Comma separated list of partition sizes in KB
|
||||
|
||||
config MIKROE_RAMMTD
|
||||
bool "MTD driver for SMARTFS RAM disk"
|
||||
default n
|
||||
select MTD
|
||||
select RAMMTD
|
||||
---help---
|
||||
Configures an MTD based RAM device for use with SMARTFS.
|
||||
|
||||
config MIKROE_RAMMTD_MINOR
|
||||
int "Minor number for RAM /dev/smart entry"
|
||||
default 1
|
||||
depends on MIKROE_RAMMTD
|
||||
---help---
|
||||
Sets the minor number for the RAM MTD /dev entry
|
||||
|
||||
config MIKROE_RAMMTD_SIZE
|
||||
int "Size in KB of the RAM device to create"
|
||||
default 32
|
||||
depends on MIKROE_RAMMTD
|
||||
---help---
|
||||
Sets the size of static RAM allocation for the SMART RAM device
|
||||
|
||||
config PM_ALARM_SEC
|
||||
int "PM_STANDBY delay (seconds)"
|
||||
default 15
|
||||
depends on PM && RTC_ALARM
|
||||
--help---
|
||||
---help---
|
||||
Number of seconds to wait in PM_STANDBY before going to PM_STANDBY mode.
|
||||
|
||||
config PM_ALARM_NSEC
|
||||
int "PM_STANDBY delay (nanoseconds)"
|
||||
default 0
|
||||
depends on PM && RTC_ALARM
|
||||
--help---
|
||||
---help---
|
||||
Number of additional nanoseconds to wait in PM_STANDBY before going to PM_STANDBY mode.
|
||||
|
||||
config PM_SLEEP_WAKEUP
|
||||
bool "PM_SLEEP wake-up alarm"
|
||||
default n
|
||||
depends on PM && RTC_ALARM
|
||||
--help---
|
||||
---help---
|
||||
Wake-up of PM_SLEEP mode after a delay and resume normal operation.
|
||||
|
||||
config PM_SLEEP_WAKEUP_SEC
|
||||
int "PM_SLEEP delay (seconds)"
|
||||
default 10
|
||||
depends on PM && RTC_ALARM
|
||||
--help---
|
||||
---help---
|
||||
Number of seconds to wait in PM_SLEEP before going to PM_STANDBY mode.
|
||||
|
||||
config PM_SLEEP_WAKEUP_NSEC
|
||||
int "PM_SLEEP delay (nanoseconds)"
|
||||
default 0
|
||||
depends on PM && RTC_ALARM
|
||||
--help---
|
||||
---help---
|
||||
Number of additional nanoseconds to wait in PM_SLEEP before going to PM_STANDBY mode.
|
||||
|
||||
endif
|
||||
|
|
|
@ -2,7 +2,20 @@ README
|
|||
======
|
||||
|
||||
This README discusses issues unique to NuttX configurations for the
|
||||
MikroElektronika Mikromedia for STM32F4 development board.
|
||||
MikroElektronika Mikromedia for STM32F4 development board. This is
|
||||
another board support by NuttX that uses the same STM32F407VGT6 MCU
|
||||
as does the STM32F4-Discovery board. This board, however, has very
|
||||
different on-board peripherals than does the STM32F4-Discovery:
|
||||
|
||||
- TFT display with touch panel,
|
||||
- VS1053 stereo audio codec with headphone jack,
|
||||
- SD card slot,
|
||||
- Serial FLASH memory,
|
||||
- USB OTG FS with micro-AB connector, and
|
||||
- Battery connect and batter charger circuit.
|
||||
|
||||
See the http://www.mikroe.com/mikromedia/stm32-m4/ for more information
|
||||
about this board.
|
||||
|
||||
Contents
|
||||
========
|
||||
|
|
|
@ -128,9 +128,14 @@
|
|||
# define CONFIG_EXAMPLES_SMART_NEBLOCKS (22)
|
||||
# endif
|
||||
|
||||
# undef CONFIG_EXAMPLES_SMART_BUFSIZE
|
||||
# define CONFIG_EXAMPLES_SMART_BUFSIZE \
|
||||
(CONFIG_RAMMTD_ERASESIZE * CONFIG_EXAMPLES_SMART_NEBLOCKS)
|
||||
#ifdef CONFIG_MIKROE_RAMMTD
|
||||
# ifndef CONFIG_MIKROE_RAMMTD_MINOR
|
||||
# define CONFIG_MIKROE_RAMMTD_MINOR 1
|
||||
# endif
|
||||
# ifndef CONFIG_MIKROE_RAMMTD_SIZE
|
||||
# define CONFIG_MIKROE_RAMMTD_SIZE 32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Debug ********************************************************************/
|
||||
|
||||
|
@ -151,11 +156,6 @@
|
|||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
/* Pre-allocated simulated flash */
|
||||
|
||||
#ifdef CONFIG_RAMMTD
|
||||
//static uint8_t g_simflash[CONFIG_EXAMPLES_SMART_BUFSIZE];
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -197,7 +197,7 @@ int nsh_archinitialize(void)
|
|||
|
||||
/* Now bind the SPI interface to the M25P8 SPI FLASH driver */
|
||||
|
||||
#ifdef CONFIG_MTD
|
||||
#if defined(CONFIG_MTD) && defined(CONFIG_MIKROE_FLASH)
|
||||
message("nsh_archinitialize: Bind SPI to the SPI flash driver\n");
|
||||
mtd = m25p_initialize(spi);
|
||||
if (!mtd)
|
||||
|
@ -208,28 +208,78 @@ int nsh_archinitialize(void)
|
|||
{
|
||||
message("nsh_archinitialize: Successfully bound SPI port 3 to the SPI FLASH driver\n");
|
||||
|
||||
/* Now initialize a SMART Flash block device and bind it to the MTD device */
|
||||
#ifdef CONFIG_MIKROE_FLASH_PART
|
||||
{
|
||||
int partno;
|
||||
int partsize;
|
||||
int partoffset;
|
||||
const char *partstring = CONFIG_MIKROE_FLASH_PART_LIST;
|
||||
const char *ptr;
|
||||
FAR struct mtd_dev_s *mtd_part;
|
||||
char partname[4];
|
||||
|
||||
/* Now create a partition on the FLASH device */
|
||||
|
||||
partno = 0;
|
||||
ptr = partstring;
|
||||
partoffset = 0;
|
||||
while (*ptr != '\0')
|
||||
{
|
||||
/* Get the partition size */
|
||||
|
||||
partsize = atoi(ptr);
|
||||
mtd_part = mtd_partition(mtd, partoffset, (partsize>>2)*16);
|
||||
partoffset += (partsize >> 2) * 16;
|
||||
|
||||
/* Now initialize a SMART Flash block device and bind it to the MTD device */
|
||||
|
||||
#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS)
|
||||
smart_initialize(0, mtd);
|
||||
sprintf(partname, "p%d", partno);
|
||||
smart_initialize(CONFIG_MIKROE_FLASH_MINOR, mtd_part, partname);
|
||||
#endif
|
||||
|
||||
/* Update the pointer to point to the next size in the list */
|
||||
|
||||
while ((*ptr >= '0') && (*ptr <= '9'))
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (*ptr == ',')
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Increment the part number */
|
||||
|
||||
partno++;
|
||||
}
|
||||
}
|
||||
#else /* CONFIG_MIKROE_FLASH_PART */
|
||||
|
||||
/* Configure the device with no partition support */
|
||||
|
||||
smart_initialize(CONFIG_MIKROE_FLASH_MINOR, mtd, NULL);
|
||||
|
||||
#endif /* CONFIG_MIKROE_FLASH_PART */
|
||||
}
|
||||
|
||||
/* Create a RAM MTD device if configured */
|
||||
|
||||
#ifdef CONFIG_RAMMTD
|
||||
#if defined(CONFIG_RAMMTD) && defined(CONFIG_MIKROE_RAMMTD)
|
||||
{
|
||||
uint8_t *start = (uint8_t *) kmalloc(CONFIG_EXAMPLES_SMART_BUFSIZE);
|
||||
mtd = rammtd_initialize(start, CONFIG_EXAMPLES_SMART_BUFSIZE);
|
||||
uint8_t *start = (uint8_t *) kmalloc(CONFIG_MIKROE_RAMMTD_SIZE * 1024);
|
||||
mtd = rammtd_initialize(start, CONFIG_MIKROE_RAMMTD_SIZE * 1024);
|
||||
mtd->ioctl(mtd, MTDIOC_BULKERASE, 0);
|
||||
|
||||
/* Now initialize a SMART Flash block device and bind it to the MTD device */
|
||||
|
||||
#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS)
|
||||
smart_initialize(1, mtd);
|
||||
smart_initialize(CONFIG_MIKROE_RAMMTD_MINOR, mtd, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RAMMTD */
|
||||
#endif /* CONFIG_RAMMTD && CONFIG_MIKROE_RAMMTD */
|
||||
|
||||
#endif /* CONFIG_MTD */
|
||||
#endif /* CONFIG_STM32_SPI3 */
|
||||
|
|
|
@ -16,7 +16,7 @@ CONFIG_HOST_LINUX=y
|
|||
#
|
||||
# Build Configuration
|
||||
#
|
||||
# CONFIG_APPS_DIR="../apps"
|
||||
CONFIG_APPS_DIR="../apps"
|
||||
# CONFIG_BUILD_2PASS is not set
|
||||
|
||||
#
|
||||
|
@ -38,27 +38,8 @@ CONFIG_RAW_BINARY=y
|
|||
#
|
||||
# Debug Options
|
||||
#
|
||||
CONFIG_DEBUG=y
|
||||
# CONFIG_DEBUG_VERBOSE is not set
|
||||
|
||||
#
|
||||
# Subsystem Debug Options
|
||||
#
|
||||
# CONFIG_DEBUG_MM is not set
|
||||
# CONFIG_DEBUG_SCHED is not set
|
||||
# CONFIG_DEBUG_USB is not set
|
||||
CONFIG_DEBUG_FS=y
|
||||
# CONFIG_DEBUG_LIB is not set
|
||||
# CONFIG_DEBUG_BINFMT is not set
|
||||
# CONFIG_DEBUG_GRAPHICS is not set
|
||||
|
||||
#
|
||||
# Driver Debug Options
|
||||
#
|
||||
# CONFIG_DEBUG_ANALOG is not set
|
||||
# CONFIG_DEBUG_SPI is not set
|
||||
# CONFIG_DEBUG_GPIO is not set
|
||||
CONFIG_DEBUG_SYMBOLS=y
|
||||
# CONFIG_DEBUG is not set
|
||||
# CONFIG_DEBUG_SYMBOLS is not set
|
||||
|
||||
#
|
||||
# System Type
|
||||
|
@ -104,7 +85,6 @@ CONFIG_ARCH_HAVE_CMNVECTOR=y
|
|||
# CONFIG_ARCH_FPU is not set
|
||||
CONFIG_ARCH_HAVE_MPU=y
|
||||
# CONFIG_ARMV7M_MPU is not set
|
||||
# CONFIG_DEBUG_HARDFAULT is not set
|
||||
|
||||
#
|
||||
# ARMV7M Configuration Options
|
||||
|
@ -310,6 +290,13 @@ CONFIG_NSH_MMCSDSPIPORTNO=0
|
|||
#
|
||||
# Board-Specific Options
|
||||
#
|
||||
CONFIG_MIKROE_FLASH=y
|
||||
CONFIG_MIKROE_FLASH_MINOR=0
|
||||
CONFIG_MIKROE_FLASH_PART=y
|
||||
CONFIG_MIKROE_FLASH_PART_LIST="256,768"
|
||||
CONFIG_MIKROE_RAMMTD=y
|
||||
CONFIG_MIKROE_RAMMTD_MINOR=1
|
||||
CONFIG_MIKROE_RAMMTD_SIZE=32
|
||||
|
||||
#
|
||||
# RTOS Features
|
||||
|
@ -408,21 +395,27 @@ CONFIG_MMCSD_SPI=y
|
|||
CONFIG_MMCSD_SPICLOCK=20000000
|
||||
# CONFIG_MMCSD_SDIO is not set
|
||||
CONFIG_MTD=y
|
||||
# CONFIG_MTD_PARTITION is not set
|
||||
|
||||
#
|
||||
# MTD Configuration
|
||||
#
|
||||
CONFIG_MTD_PARTITION=y
|
||||
CONFIG_MTD_BYTE_WRITE=y
|
||||
|
||||
#
|
||||
# MTD Device Drivers
|
||||
#
|
||||
CONFIG_RAMMTD=y
|
||||
CONFIG_RAMMTD_BLOCKSIZE=512
|
||||
CONFIG_RAMMTD_ERASESIZE=4096
|
||||
CONFIG_RAMMTD_ERASESTATE=0xff
|
||||
# CONFIG_RAMMTD_FLASHSIM is not set
|
||||
CONFIG_RAMMTD_SMART=y
|
||||
# CONFIG_MTD_AT24XX is not set
|
||||
# CONFIG_MTD_AT45DB is not set
|
||||
CONFIG_MTD_M25P=y
|
||||
CONFIG_M25P_SPIMODE=0
|
||||
CONFIG_M25P_MANUFACTURER=0x1C
|
||||
CONFIG_M25P_MEMORY_TYPE=0x31
|
||||
CONFIG_M25P_SUBSECTOR_ERASE=y
|
||||
CONFIG_M25P_BYTEWRITE=y
|
||||
CONFIG_MTD_SMART=y
|
||||
CONFIG_MTD_SMART_SECTOR_SIZE=512
|
||||
# CONFIG_MTD_RAMTRON is not set
|
||||
|
@ -441,7 +434,6 @@ CONFIG_SERIAL_REMOVABLE=y
|
|||
CONFIG_ARCH_HAVE_USART2=y
|
||||
CONFIG_MCU_SERIAL=y
|
||||
CONFIG_STANDARD_SERIAL=y
|
||||
# CONFIG_SERIAL_TIOCSERGSTRUCT is not set
|
||||
# CONFIG_USART2_SERIAL_CONSOLE is not set
|
||||
CONFIG_NO_SERIAL_CONSOLE=y
|
||||
|
||||
|
@ -529,7 +521,7 @@ CONFIG_FS_ROMFS=y
|
|||
CONFIG_FS_SMARTFS=y
|
||||
CONFIG_SMARTFS_ERASEDSTATE=0xff
|
||||
CONFIG_SMARTFS_MAXNAMLEN=16
|
||||
CONFIG_SMARTFS_MULTI_ROOT_DIRS=y
|
||||
# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set
|
||||
# CONFIG_FS_BINFS is not set
|
||||
|
||||
#
|
||||
|
@ -650,6 +642,7 @@ CONFIG_EXAMPLES_NSH=y
|
|||
# CONFIG_EXAMPLES_NX is not set
|
||||
# CONFIG_EXAMPLES_NXCONSOLE is not set
|
||||
# CONFIG_EXAMPLES_NXFFS is not set
|
||||
# CONFIG_EXAMPLES_SMART is not set
|
||||
# CONFIG_EXAMPLES_NXFLAT is not set
|
||||
# CONFIG_EXAMPLES_NXHELLO is not set
|
||||
# CONFIG_EXAMPLES_NXIMAGE is not set
|
||||
|
@ -664,8 +657,8 @@ CONFIG_EXAMPLES_NSH=y
|
|||
# CONFIG_EXAMPLES_ROMFS is not set
|
||||
# CONFIG_EXAMPLES_SENDMAIL is not set
|
||||
# CONFIG_EXAMPLES_SERLOOP is not set
|
||||
CONFIG_EXAMPLES_FLASH_TEST=y
|
||||
CONFIG_EXAMPLES_SMART_TEST=y
|
||||
# CONFIG_EXAMPLES_FLASH_TEST is not set
|
||||
# CONFIG_EXAMPLES_SMART_TEST is not set
|
||||
# CONFIG_EXAMPLES_TELNETD is not set
|
||||
# CONFIG_EXAMPLES_THTTPD is not set
|
||||
# CONFIG_EXAMPLES_TIFF is not set
|
||||
|
@ -774,23 +767,13 @@ CONFIG_NSH_LINELEN=64
|
|||
CONFIG_NSH_NESTDEPTH=3
|
||||
# CONFIG_NSH_DISABLESCRIPT is not set
|
||||
# CONFIG_NSH_DISABLEBG is not set
|
||||
CONFIG_NSH_ROMFSETC=y
|
||||
# CONFIG_NSH_ROMFSRC is not set
|
||||
CONFIG_NSH_ROMFSMOUNTPT="/etc"
|
||||
CONFIG_NSH_INITSCRIPT="init.d/rcS"
|
||||
CONFIG_NSH_ROMFSDEVNO=0
|
||||
CONFIG_NSH_ROMFSSECTSIZE=64
|
||||
CONFIG_NSH_FATDEVNO=0
|
||||
CONFIG_NSH_FATSECTSIZE=512
|
||||
CONFIG_NSH_FATNSECTORS=1024
|
||||
CONFIG_NSH_FATMOUNTPT="/tmp"
|
||||
# CONFIG_NSH_ROMFSETC is not set
|
||||
CONFIG_NSH_CONSOLE=y
|
||||
# CONFIG_NSH_USBCONSOLE is not set
|
||||
|
||||
#
|
||||
# USB Trace Support
|
||||
#
|
||||
# CONFIG_NSH_USBDEV_TRACE is not set
|
||||
# CONFIG_NSH_CONDEV is not set
|
||||
CONFIG_NSH_ARCHINIT=y
|
||||
|
||||
|
|
|
@ -2,7 +2,20 @@ README
|
|||
======
|
||||
|
||||
This README discusses issues unique to NuttX configurations for the
|
||||
STMicro STM32F4Discovery development board.
|
||||
STMicro STM32F4Discovery development board featuring the STM32F407VGT6
|
||||
MCU. The STM32F407VGT6 is a 168MHz Cortex-M4 operation with 1Mbit Flash
|
||||
memory and 128kbytes. The board features:
|
||||
|
||||
- On-board ST-LINK/V2 for programming and debugging,
|
||||
- LIS302DL, ST MEMS motion sensor, 3-axis digital output accelerometer,
|
||||
- MP45DT02, ST MEMS audio sensor, omni-directional digital microphone,
|
||||
- CS43L22, audio DAC with integrated class D speaker driver,
|
||||
- Eight LEDs and two push-buttons,
|
||||
- USB OTG FS with micro-AB connector, and
|
||||
- Easy access to most MCU pins.
|
||||
|
||||
Refer to http://www.st.com/internet/evalboard/product/252419.jsp for
|
||||
further information about this board.
|
||||
|
||||
Contents
|
||||
========
|
||||
|
|
|
@ -64,13 +64,6 @@ config RAMMTD_FLASHSIM
|
|||
RAMMTD_FLASHSIM will add some extra logic to improve the level of
|
||||
FLASH simulation.
|
||||
|
||||
config RAMMTD_SMART
|
||||
bool "SMART block driver support in the RAM MTD driver"
|
||||
default n
|
||||
---help---
|
||||
Builds in additional ioctl and interface code to support the
|
||||
SMART block driver / filesystem.
|
||||
|
||||
endif
|
||||
|
||||
config MTD_AT24XX
|
||||
|
@ -139,30 +132,14 @@ config M25P_MEMORY_TYPE
|
|||
---help---
|
||||
The memory type for M25 "P" series is 0x20, but the driver also supports "F" series
|
||||
devices, such as the EON EN25F80 part which adds a 4K sector erase capability. The
|
||||
ID for "F" series parts from EON is 0x31.
|
||||
|
||||
config M25P_SUBSECTOR_ERASE
|
||||
bool "Sub-Sector Erase"
|
||||
default n
|
||||
---help---
|
||||
Some devices (such as the EON EN25F80) support a smaller erase block
|
||||
size (4K vs 64K). This option enables support for sub-sector erase.
|
||||
The SMART file system can take advantage of this option if it is enabled.
|
||||
|
||||
config M25P_BYTEWRITE
|
||||
bool "Enable ByteWrite ioctl support"
|
||||
default n
|
||||
---help---
|
||||
The M25P series of devices allow writing to a page with less than a full-page
|
||||
size of data. In this case, only the written bytes are updated without affecting
|
||||
the other bytes in the page. The SMART FS requires this option for proper operation.
|
||||
memory type for "F" series parts from EON is 0x31. The 4K sector erase size will
|
||||
automatically be enabled when filessytems that can use it are enabled, such as SMART.
|
||||
|
||||
endif
|
||||
|
||||
config MTD_SMART
|
||||
bool "Sector Mapped Allocation for Really Tiny (SMART) Flash support"
|
||||
default y
|
||||
select M25P_BYTEWRITE
|
||||
---help---
|
||||
The MP25x series of Flash devices are typically very small and have a very large
|
||||
erase block size. This causes issues with the standard Flash Translation Layer
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Driver for SPI-based M25P1 (128Kbit), M25P64 (32Mbit), M25P64 (64Mbit), and
|
||||
* M25P128 (128Mbit) FLASH (and compatible).
|
||||
*
|
||||
* Copyright (C) 2009-2011 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2009-2011, 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -114,6 +114,7 @@
|
|||
#define M25P_EN25F80_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
|
||||
#define M25P_EN25F80_NPAGES 4096
|
||||
#define M25P_EN25F80_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */
|
||||
#define M25P_EN25F80_NSUBSECTORS 256
|
||||
|
||||
/* M25P32 capacity is 4,194,304 bytes:
|
||||
* (64 sectors) * (65,536 bytes per sector)
|
||||
|
@ -203,7 +204,7 @@ struct m25p_dev_s
|
|||
uint8_t pageshift; /* 8 */
|
||||
uint16_t nsectors; /* 128 or 64 */
|
||||
uint32_t npages; /* 32,768 or 65,536 */
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
uint8_t subsectorshift; /* 0, 12 or 13 (4K or 8K) */
|
||||
#endif
|
||||
};
|
||||
|
@ -219,13 +220,10 @@ static inline void m25p_unlock(FAR struct spi_dev_s *dev);
|
|||
static inline int m25p_readid(struct m25p_dev_s *priv);
|
||||
static void m25p_waitwritecomplete(struct m25p_dev_s *priv);
|
||||
static void m25p_writeenable(struct m25p_dev_s *priv);
|
||||
static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t offset);
|
||||
static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t offset, uint8_t type);
|
||||
static inline int m25p_bulkerase(struct m25p_dev_s *priv);
|
||||
static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer,
|
||||
off_t offset);
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
static inline void m25p_subsectorerase(struct m25p_dev_s *priv, off_t offset);
|
||||
#endif
|
||||
|
||||
/* MTD driver methods */
|
||||
|
||||
|
@ -236,6 +234,10 @@ static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
|
|||
size_t nblocks, FAR const uint8_t *buf);
|
||||
static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
|
||||
FAR uint8_t *buffer);
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
static ssize_t m25p_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
|
||||
FAR const uint8_t *buffer);
|
||||
#endif
|
||||
static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
|
||||
|
||||
/************************************************************************************
|
||||
|
@ -320,7 +322,7 @@ static inline int m25p_readid(struct m25p_dev_s *priv)
|
|||
{
|
||||
/* Okay.. is it a FLASH capacity that we understand? */
|
||||
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
priv->subsectorshift = 0;
|
||||
#endif
|
||||
|
||||
|
@ -338,11 +340,11 @@ static inline int m25p_readid(struct m25p_dev_s *priv)
|
|||
{
|
||||
/* Save the FLASH geometry */
|
||||
|
||||
priv->sectorshift = M25P_EN25F80_SECTOR_SHIFT;
|
||||
priv->nsectors = M25P_EN25F80_NSECTORS;
|
||||
priv->pageshift = M25P_EN25F80_PAGE_SHIFT;
|
||||
priv->npages = M25P_EN25F80_NPAGES;
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
priv->sectorshift = M25P_EN25F80_SECTOR_SHIFT;
|
||||
priv->nsectors = M25P_EN25F80_NSECTORS;
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
priv->subsectorshift = M25P_EN25F80_SUBSECT_SHIFT;
|
||||
#endif
|
||||
return OK;
|
||||
|
@ -480,9 +482,20 @@ static void m25p_writeenable(struct m25p_dev_s *priv)
|
|||
* Name: m25p_sectorerase
|
||||
************************************************************************************/
|
||||
|
||||
static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector)
|
||||
static void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector, uint8_t type)
|
||||
{
|
||||
off_t offset = sector << priv->sectorshift;
|
||||
off_t offset;
|
||||
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
if (priv->subsectorshift > 0)
|
||||
{
|
||||
offset = sector << priv->subsectorshift;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
offset = sector << priv->sectorshift;
|
||||
}
|
||||
|
||||
fvdbg("sector: %08lx\n", (long)sector);
|
||||
|
||||
|
@ -502,9 +515,11 @@ static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector)
|
|||
|
||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
|
||||
|
||||
/* Send the "Sector Erase (SE)" instruction */
|
||||
/* Send the "Sector Erase (SE)" or Sub-Sector Erase (SSE) instruction
|
||||
* that was passed in as the erase type.
|
||||
*/
|
||||
|
||||
(void)SPI_SEND(priv->dev, M25P_SE);
|
||||
(void)SPI_SEND(priv->dev, type);
|
||||
|
||||
/* Send the sector offset high byte first. For all of the supported
|
||||
* parts, the sector number is completely contained in the first byte
|
||||
|
@ -521,53 +536,6 @@ static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector)
|
|||
fvdbg("Erased\n");
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: m25p_subsectorerase
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
static inline void m25p_subsectorerase(struct m25p_dev_s *priv, off_t subsector)
|
||||
{
|
||||
off_t offset = subsector << priv->subsectorshift;
|
||||
|
||||
fvdbg("subsector: %9lx\n", (long)subsector);
|
||||
|
||||
/* Wait for any preceding write to complete. We could simplify things by
|
||||
* perform this wait at the end of each write operation (rather than at
|
||||
* the beginning of ALL operations), but have the wait first will slightly
|
||||
* improve performance.
|
||||
*/
|
||||
|
||||
m25p_waitwritecomplete(priv);
|
||||
|
||||
/* Send write enable instruction */
|
||||
|
||||
m25p_writeenable(priv);
|
||||
|
||||
/* Select this FLASH part */
|
||||
|
||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
|
||||
|
||||
/* Send the "Sub-Sector Erase (SSE)" instruction */
|
||||
|
||||
(void)SPI_SEND(priv->dev, M25P_SSE);
|
||||
|
||||
/* Send the sector offset high byte first. For all of the supported
|
||||
* parts, the sector number is completely contained in the first byte
|
||||
* and the values used in the following two bytes don't really matter.
|
||||
*/
|
||||
|
||||
(void)SPI_SEND(priv->dev, (offset >> 16) & 0xff);
|
||||
(void)SPI_SEND(priv->dev, (offset >> 8) & 0xff);
|
||||
(void)SPI_SEND(priv->dev, offset & 0xff);
|
||||
|
||||
/* Deselect the FLASH */
|
||||
|
||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
|
||||
fvdbg("Erased\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: m25p_bulkerase
|
||||
************************************************************************************/
|
||||
|
@ -654,7 +622,7 @@ static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const uint8_t *bu
|
|||
* Name: m25p_bytewrite
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_M25P_BYTEWRITE
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
static inline void m25p_bytewrite(struct m25p_dev_s *priv, FAR const uint8_t *buffer,
|
||||
off_t offset, uint16_t count)
|
||||
{
|
||||
|
@ -711,13 +679,55 @@ static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock
|
|||
/* Lock access to the SPI bus until we complete the erase */
|
||||
|
||||
m25p_lock(priv->dev);
|
||||
while (blocksleft-- > 0)
|
||||
while (blocksleft > 0)
|
||||
{
|
||||
/* Erase each sector */
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
size_t sectorboundry;
|
||||
size_t blkper;
|
||||
|
||||
m25p_sectorerase(priv, startblock);
|
||||
/* If we have a smaller erase size, then we will find as many full
|
||||
* sector erase blocks as possible to speed up the process instead of
|
||||
* erasing everything in smaller chunks.
|
||||
*/
|
||||
|
||||
if (priv->subsectorshift > 0)
|
||||
{
|
||||
blkper = 1 << (priv->sectorshift - priv->subsectorshift);
|
||||
sectorboundry = (startblock + blkper - 1) / blkper;
|
||||
sectorboundry *= blkper;
|
||||
|
||||
/* If we are on a sector boundry and have at least a full sector
|
||||
* of blocks left to erase, then we can do a full sector erase.
|
||||
*/
|
||||
|
||||
if (startblock == sectorboundry && blocksleft >= blkper)
|
||||
{
|
||||
/* Do a full sector erase */
|
||||
|
||||
m25p_sectorerase(priv, startblock / blkper, M25P_SE);
|
||||
startblock += blkper;
|
||||
blocksleft -= blkper;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just do a sub-sector erase */
|
||||
|
||||
m25p_sectorerase(priv, startblock, M25P_SSE);
|
||||
startblock++;
|
||||
blocksleft--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Not using sub-sector erase. Erase each full sector */
|
||||
|
||||
m25p_sectorerase(priv, startblock, M25P_SE);
|
||||
startblock++;
|
||||
blocksleft--;
|
||||
}
|
||||
|
||||
m25p_unlock(priv->dev);
|
||||
return (int)nblocks;
|
||||
}
|
||||
|
@ -741,6 +751,7 @@ static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nb
|
|||
{
|
||||
return nbytes >> priv->pageshift;
|
||||
}
|
||||
|
||||
return (int)nbytes;
|
||||
}
|
||||
|
||||
|
@ -766,8 +777,8 @@ static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t n
|
|||
buffer += pagesize;
|
||||
startblock++;
|
||||
}
|
||||
m25p_unlock(priv->dev);
|
||||
|
||||
m25p_unlock(priv->dev);
|
||||
return nblocks;
|
||||
}
|
||||
|
||||
|
@ -817,6 +828,78 @@ static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
|
|||
return nbytes;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: m25p_write
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
static ssize_t m25p_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
|
||||
FAR const uint8_t *buffer)
|
||||
{
|
||||
FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev;
|
||||
int startpage;
|
||||
int endpage;
|
||||
int count;
|
||||
int index;
|
||||
int pagesize;
|
||||
int bytestowrite;
|
||||
|
||||
fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
|
||||
|
||||
/* We must test if the offset + count crosses one or more pages
|
||||
* and perform individual writes. The devices can only write in
|
||||
* page increments.
|
||||
*/
|
||||
|
||||
startpage = offset / (1 << priv->pageshift);
|
||||
endpage = (offset + nbytes) / (1 << priv->pageshift);
|
||||
|
||||
if (startpage == endpage)
|
||||
{
|
||||
/* All bytes within one programmable page. Just do the write. */
|
||||
|
||||
m25p_bytewrite(priv, buffer, offset, nbytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write the 1st partial-page */
|
||||
|
||||
count = nbytes;
|
||||
pagesize = (1 << priv->pageshift);
|
||||
bytestowrite = pagesize - (offset & (pagesize-1));
|
||||
m25p_bytewrite(priv, buffer, offset, bytestowrite);
|
||||
|
||||
/* Update offset and count */
|
||||
|
||||
offset += bytestowrite;
|
||||
count -= bytestowrite;
|
||||
index = bytestowrite;
|
||||
|
||||
/* Write full pages */
|
||||
|
||||
while (count >= pagesize)
|
||||
{
|
||||
m25p_bytewrite(priv, &buffer[index], offset, pagesize);
|
||||
|
||||
/* Update offset and count */
|
||||
|
||||
offset += pagesize;
|
||||
count -= pagesize;
|
||||
index += pagesize;
|
||||
}
|
||||
|
||||
/* Now write any partial page at the end */
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
m25p_bytewrite(priv, &buffer[index], offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
#endif /* CONFIG_MTD_BYTE_WRITE */
|
||||
|
||||
/************************************************************************************
|
||||
* Name: m25p_ioctl
|
||||
************************************************************************************/
|
||||
|
@ -844,15 +927,22 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||
* appear so.
|
||||
*/
|
||||
|
||||
geo->blocksize = (1 << priv->pageshift);
|
||||
geo->erasesize = (1 << priv->sectorshift);
|
||||
geo->neraseblocks = priv->nsectors;
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
geo->subsectorsize = (1 << priv->subsectorshift);
|
||||
geo->nsubsectors = priv->nsectors * (1 << (priv->sectorshift -
|
||||
priv->subsectorshift));
|
||||
geo->blocksize = (1 << priv->pageshift);
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
if (priv->subsectorshift > 0)
|
||||
{
|
||||
geo->erasesize = (1 << priv->subsectorshift);
|
||||
geo->neraseblocks = priv->nsectors * (1 << (priv->sectorshift -
|
||||
priv->subsectorshift));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
ret = OK;
|
||||
{
|
||||
geo->erasesize = (1 << priv->sectorshift);
|
||||
geo->neraseblocks = priv->nsectors;
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
|
||||
fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
|
||||
geo->blocksize, geo->erasesize, geo->neraseblocks);
|
||||
|
@ -870,97 +960,6 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_FS_SMARTFS
|
||||
case MTDIOC_GETCAPS:
|
||||
{
|
||||
ret = 0;
|
||||
#ifdef CONFIG_M25P_BYTEWRITE
|
||||
ret |= MTDIOC_CAPS_BYTEWRITE;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
ret |= MTDIOC_CAPS_SECTERASE;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_FS_SMARTFS */
|
||||
|
||||
#ifdef CONFIG_M25P_SUBSECTOR_ERASE
|
||||
case MTDIOC_SECTERASE:
|
||||
{
|
||||
m25p_subsectorerase(priv, (off_t) arg);
|
||||
ret = OK;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_M25P_BYTEWRITE
|
||||
case MTDIOC_BYTEWRITE:
|
||||
{
|
||||
struct mtd_byte_write_s *bytewrite = (struct mtd_byte_write_s *) arg;
|
||||
int startpage;
|
||||
int endpage;
|
||||
int count;
|
||||
int index;
|
||||
int pagesize;
|
||||
int bytestowrite;
|
||||
size_t offset;
|
||||
|
||||
/* We must test if the offset + count crosses one or more pages
|
||||
* and perform individual writes. The devices can only write in
|
||||
* page increments.
|
||||
*/
|
||||
|
||||
startpage = bytewrite->offset / (1 << priv->pageshift);
|
||||
endpage = (bytewrite->offset + bytewrite->count) / (1 << priv->pageshift);
|
||||
|
||||
if (startpage == endpage)
|
||||
{
|
||||
m25p_bytewrite(priv, bytewrite->buffer, bytewrite->offset,
|
||||
bytewrite->count);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write the 1st partial-page */
|
||||
|
||||
count = bytewrite->count;
|
||||
pagesize = (1 << priv->pageshift);
|
||||
offset = bytewrite->offset;
|
||||
bytestowrite = pagesize - (bytewrite->offset & (pagesize-1));
|
||||
m25p_bytewrite(priv, bytewrite->buffer, offset, bytestowrite);
|
||||
|
||||
/* Update offset and count */
|
||||
|
||||
offset += bytestowrite;
|
||||
count -= bytestowrite;
|
||||
index = bytestowrite;
|
||||
|
||||
/* Write full pages */
|
||||
|
||||
while (count >= pagesize)
|
||||
{
|
||||
m25p_bytewrite(priv, &bytewrite->buffer[index], offset, pagesize);
|
||||
|
||||
/* Update offset and count */
|
||||
|
||||
offset += pagesize;
|
||||
count -= pagesize;
|
||||
index += pagesize;
|
||||
}
|
||||
|
||||
/* Now write any partial page at the end */
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
m25p_bytewrite(priv, &bytewrite->buffer[index], offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case MTDIOC_XIPBASE:
|
||||
default:
|
||||
ret = -ENOTTY; /* Bad command */
|
||||
|
@ -1010,6 +1009,9 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev)
|
|||
priv->mtd.bread = m25p_bread;
|
||||
priv->mtd.bwrite = m25p_bwrite;
|
||||
priv->mtd.read = m25p_read;
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
priv->mtd.write = m25p_write;
|
||||
#endif
|
||||
priv->mtd.ioctl = m25p_ioctl;
|
||||
priv->dev = dev;
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ static bool part_bytecheck(FAR struct mtd_partition_s *priv, off_t byoff)
|
|||
|
||||
erasesize = priv->blocksize * priv->blkpererase;
|
||||
readend = (byoff + erasesize - 1) / erasesize;
|
||||
return readend < priv->neraseblocks;
|
||||
return readend <= priv->neraseblocks;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -410,6 +410,12 @@ static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||
* sector count (where the size of a sector is provided the by parent MTD
|
||||
* driver).
|
||||
*
|
||||
* NOTE: Since there may be a number of MTD partition drivers operating on
|
||||
* the same, underlying FLASH driver, that FLASH driver must be capable
|
||||
* of enforcing mutually exclusive access to the FLASH device. Without
|
||||
* partitions, that mutual exclusion would be provided by the file system
|
||||
* above the FLASH driver.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, off_t firstblock,
|
||||
|
@ -483,6 +489,9 @@ FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, off_t firstblock,
|
|||
part->child.bwrite = part_bwrite;
|
||||
part->child.read = mtd->read ? part_read : NULL;
|
||||
part->child.ioctl = part_ioctl;
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
part->child.write = mtd->write ? part_write : NULL;
|
||||
#endif
|
||||
|
||||
part->parent = mtd;
|
||||
part->firstblock = erasestart * blkpererase;
|
||||
|
|
|
@ -228,7 +228,7 @@ static int ram_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks
|
|||
* Name: ram_readbytes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RAMMTD_SMART
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
static ssize_t ram_read_bytes(FAR struct mtd_dev_s *dev, off_t offset,
|
||||
size_t nbytes, FAR uint8_t *buf)
|
||||
{
|
||||
|
@ -328,6 +328,34 @@ static ssize_t ram_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
|
|||
return nblocks;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ram_bytewrite
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
static ssize_t ram_bytewrite(FAR struct mtd_dev_s *dev, off_t offset,
|
||||
size_t nbytes, FAR const uint8_t *buf)
|
||||
{
|
||||
FAR struct ram_dev_s *priv = (FAR struct ram_dev_s *)dev;
|
||||
off_t maxaddr;
|
||||
|
||||
DEBUGASSERT(dev && buf);
|
||||
|
||||
/* Don't let the write exceed the size of the ram buffer */
|
||||
|
||||
maxaddr = priv->nblocks * CONFIG_RAMMTD_ERASESIZE;
|
||||
if (offset + nbytes > maxaddr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Then write the data to RAM */
|
||||
|
||||
ram_write(&priv->start[offset], buf, nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ram_ioctl
|
||||
****************************************************************************/
|
||||
|
@ -380,24 +408,6 @@ static int ram_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_RAMMTD_SMART
|
||||
case MTDIOC_GETCAPS:
|
||||
{
|
||||
ret = MTDIOC_CAPS_BYTEWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
case MTDIOC_BYTEWRITE:
|
||||
{
|
||||
struct mtd_byte_write_s *bytewrite = (struct mtd_byte_write_s *) arg;
|
||||
|
||||
ram_write(&priv->start[bytewrite->offset], bytewrite->buffer,
|
||||
bytewrite->count);
|
||||
ret = OK;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = -ENOTTY; /* Bad command */
|
||||
break;
|
||||
|
@ -454,9 +464,14 @@ FAR struct mtd_dev_s *rammtd_initialize(FAR uint8_t *start, size_t size)
|
|||
priv->mtd.bwrite = ram_bwrite;
|
||||
priv->mtd.ioctl = ram_ioctl;
|
||||
priv->mtd.erase = ram_erase;
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
priv->mtd.write = ram_bytewrite;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RAMMTD_SMART
|
||||
#ifdef CONFIG_MTD_SMART
|
||||
priv->mtd.read = ram_read_bytes;
|
||||
#else
|
||||
priv->mtd.read = NULL;
|
||||
#endif
|
||||
|
||||
priv->start = start;
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
|
||||
#define SMART_FMT_VERSION 1
|
||||
|
||||
#define SMART_FIRST_ALLOC_SECTOR 16 /* First logical sector number we will
|
||||
#define SMART_FIRST_ALLOC_SECTOR 12 /* First logical sector number we will
|
||||
* use for assignment of requested Alloc
|
||||
* sectors. All enries below this are
|
||||
* reserved (some for root dir entries,
|
||||
|
@ -134,6 +134,7 @@ struct smart_struct_s
|
|||
FAR uint8_t *releasecount; /* Count of released sectors per erase block */
|
||||
FAR uint8_t *freecount; /* Count of free sectors per erase block */
|
||||
FAR char *rwbuffer; /* Our sector read/write buffer */
|
||||
const FAR char *partname; /* Optional partition name */
|
||||
uint8_t formatversion; /* Format version on the device */
|
||||
uint8_t formatstatus; /* Indicates the status of the device format */
|
||||
uint8_t namesize; /* Length of filenames on this device */
|
||||
|
@ -471,49 +472,21 @@ static int smart_setsectorsize(struct smart_struct_s *dev, uint16_t size)
|
|||
{
|
||||
uint32_t erasesize;
|
||||
uint32_t totalsectors;
|
||||
int ret;
|
||||
|
||||
/* Check if the device supports sub-sector erase regions. If it does, then
|
||||
* use the sub-sector erase size instead of the larger erase size to
|
||||
* provide finer granularity.
|
||||
*/
|
||||
/* Validate the size isn't zero so we don't divide by zero below */
|
||||
|
||||
#ifdef CONFIG_MTD_SUBSECTOR_ERASE
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_GETCAPS, 0);
|
||||
if (ret >= 0)
|
||||
if (size == 0)
|
||||
{
|
||||
/* The block device supports the GETCAPS ioctl. Now check if sub-sector
|
||||
* erase is supported.
|
||||
*/
|
||||
|
||||
if (!(ret & MTDIOC_CAPS_SECTERASE))
|
||||
{
|
||||
/* Ensure the subsector size is zero */
|
||||
dev->geo.subsectorsize = 0;
|
||||
dev->geo.nsubsectors = 0;
|
||||
}
|
||||
size = CONFIG_MTD_SMART_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/* Now calculate the variables */
|
||||
|
||||
if (dev->geo.subsectorsize != 0)
|
||||
{
|
||||
/* Use the sub-sector erase size */
|
||||
|
||||
erasesize = dev->geo.subsectorsize;
|
||||
dev->neraseblocks = dev->geo.nsubsectors;
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_MTD_SUBSECTOR_ERASE */
|
||||
{
|
||||
erasesize = dev->geo.erasesize;
|
||||
dev->neraseblocks = dev->geo.neraseblocks;
|
||||
}
|
||||
erasesize = dev->geo.erasesize;
|
||||
dev->neraseblocks = dev->geo.neraseblocks;
|
||||
|
||||
/* Most FLASH devices have erase size of 64K, but geo.erasesize is only
|
||||
* 16 bits, so it will be zero
|
||||
*/
|
||||
|
||||
|
||||
if (erasesize == 0)
|
||||
{
|
||||
erasesize = 65536;
|
||||
|
@ -568,6 +541,74 @@ static int smart_setsectorsize(struct smart_struct_s *dev, uint16_t size)
|
|||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_bytewrite
|
||||
*
|
||||
* Description: Writes a non-page size count of bytes to the underlying
|
||||
* MTD device. If the MTD driver supports a direct impl of
|
||||
* write, then it uses it, otherwise it does a read-modify-write
|
||||
* and depends on the architecture of the flash to only program
|
||||
* bits that acutally changed.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t smart_bytewrite(struct smart_struct_s *dev, size_t offset,
|
||||
int nbytes, const uint8_t *buffer)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
#ifdef CONFIG_MTD_BYTE_WRITE
|
||||
/* Check if the underlying MTD device supports write */
|
||||
|
||||
if (dev->mtd->write != NULL)
|
||||
{
|
||||
/* Use the MTD's write method to write individual bytes */
|
||||
|
||||
ret = dev->mtd->write(dev->mtd, offset, nbytes, buffer);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Perform block-based read-modify-write */
|
||||
|
||||
uint16_t startblock;
|
||||
uint16_t nblocks;
|
||||
|
||||
/* First calculate the start block and number of blocks affected */
|
||||
|
||||
startblock = offset / dev->geo.blocksize;
|
||||
nblocks = (nbytes + dev->geo.blocksize-1) / dev->geo.blocksize;
|
||||
DEBUGASSERT(nblocks <= dev->mtdBlksPerSector);
|
||||
|
||||
/* Do a block read */
|
||||
|
||||
ret = MTD_BREAD(dev->mtd, startblock, nblocks, (uint8_t *) dev->rwbuffer);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d reading from device\n", -ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Modify the data */
|
||||
|
||||
memcpy(&dev->rwbuffer[offset - startblock * dev->geo.blocksize], buffer, nbytes);
|
||||
|
||||
/* Write the data back to the device */
|
||||
|
||||
ret = MTD_BWRITE(dev->mtd, startblock, nblocks, (uint8_t *) dev->rwbuffer);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d writing to device\n", -ret);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nbytes;
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_scan
|
||||
*
|
||||
|
@ -581,17 +622,17 @@ static int smart_scan(struct smart_struct_s *dev)
|
|||
{
|
||||
int sector;
|
||||
int ret;
|
||||
int x;
|
||||
int offset;
|
||||
uint16_t totalsectors;
|
||||
uint16_t sectorsize;
|
||||
uint16_t logicalsector;
|
||||
uint16_t seq1;
|
||||
uint16_t seq2;
|
||||
char devname[18];
|
||||
size_t readaddress;
|
||||
struct smart_sect_header_s header;
|
||||
struct mtd_byte_write_s bytewrite;
|
||||
#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS
|
||||
int x;
|
||||
char devname[22];
|
||||
struct smart_multiroot_device_s *rootdirdev;
|
||||
#endif
|
||||
|
||||
|
@ -675,7 +716,7 @@ static int smart_scan(struct smart_struct_s *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Test if this sector has been commited */
|
||||
/* Test if this sector has been committed */
|
||||
|
||||
if ((header.status & SMART_STATUS_COMMITTED) ==
|
||||
(CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_COMMITTED))
|
||||
|
@ -763,7 +804,16 @@ static int smart_scan(struct smart_struct_s *dev)
|
|||
|
||||
for (x = 1; x < dev->rootdirentries; x++)
|
||||
{
|
||||
snprintf(devname, 18, "/dev/smart%dd%d", dev->minor, x + 1);
|
||||
if (dev->partname != NULL)
|
||||
{
|
||||
snprintf(dev->rwbuffer, sizeof(devname), "/dev/smart%d%s%d",
|
||||
dev->minor, dev->partname, x+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(devname, sizeof(devname), "/dev/smart%dd%d", dev->minor,
|
||||
x + 1);
|
||||
}
|
||||
|
||||
/* Inode private data is a reference to a struct containing
|
||||
* the SMART device structure and the root directory number.
|
||||
|
@ -792,9 +842,9 @@ static int smart_scan(struct smart_struct_s *dev)
|
|||
|
||||
/* Test for duplicate logical sectors on the device */
|
||||
|
||||
if (dev->sMap[logicalsector] != -1)
|
||||
if (dev->sMap[logicalsector] != 0xFFFF)
|
||||
{
|
||||
/* TODO: Uh-oh, we found more than 1 physical sector claiming to be
|
||||
/* Uh-oh, we found more than 1 physical sector claiming to be
|
||||
* the * same logical sector. Use the sequence number information
|
||||
* to resolve who wins.
|
||||
*/
|
||||
|
@ -853,10 +903,13 @@ static int smart_scan(struct smart_struct_s *dev)
|
|||
#else
|
||||
header.status |= SMART_STATUS_RELEASED;
|
||||
#endif
|
||||
bytewrite.offset = readaddress + offsetof(struct smart_sect_header_s, status);
|
||||
bytewrite.count = 1;
|
||||
bytewrite.buffer = &header.status;
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
offset = readaddress + offsetof(struct smart_sect_header_s, status);
|
||||
ret = smart_bytewrite(dev, offset, 1, &header.status);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d releasing duplicate sector\n", -ret);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the logical to physical sector map */
|
||||
|
@ -886,9 +939,11 @@ err_out:
|
|||
|
||||
#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS
|
||||
static inline int smart_getformat(struct smart_struct_s *dev,
|
||||
struct smart_format_s *fmt, uint8_t rootdirnum)
|
||||
struct smart_format_s *fmt,
|
||||
uint8_t rootdirnum)
|
||||
#else
|
||||
static inline int smart_getformat(struct smart_struct_s *dev, struct smart_format_s *fmt)
|
||||
static inline int smart_getformat(struct smart_struct_s *dev,
|
||||
struct smart_format_s *fmt)
|
||||
#endif
|
||||
{
|
||||
int ret;
|
||||
|
@ -914,8 +969,6 @@ static inline int smart_getformat(struct smart_struct_s *dev, struct smart_forma
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: Determine if the underlying MTD device supports bytewrite */
|
||||
|
||||
/* Now fill in the structure */
|
||||
|
||||
if (dev->formatstatus == SMART_FMT_STAT_FORMATTED)
|
||||
|
@ -978,7 +1031,7 @@ static inline int smart_llformat(struct smart_struct_s *dev, unsigned long arg)
|
|||
/* Erase the MTD device */
|
||||
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BULKERASE, 0);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
@ -1180,8 +1233,9 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
bool collect = TRUE;
|
||||
int x;
|
||||
int ret;
|
||||
size_t offset;
|
||||
struct smart_sect_header_s *header;
|
||||
struct mtd_byte_write_s bytewrite;
|
||||
uint8_t newstatus;
|
||||
|
||||
while (collect)
|
||||
{
|
||||
|
@ -1196,8 +1250,6 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
{
|
||||
releasedsectors += dev->releasecount[x];
|
||||
if (dev->releasecount[x] > releasemax)
|
||||
// if (dev->releasecount[x] > releasemax &&
|
||||
// dev->freecount[x] < (dev->sectorsPerBlk >> 1))
|
||||
{
|
||||
releasemax = dev->releasecount[x];
|
||||
collectblock = x;
|
||||
|
@ -1205,7 +1257,8 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
}
|
||||
|
||||
/* Test if the released sectors count is greater than the
|
||||
* free sectors. If it is, then we will do garbage collection */
|
||||
* free sectors. If it is, then we will do garbage collection.
|
||||
*/
|
||||
|
||||
if (releasedsectors > dev->freesectors)
|
||||
collect = TRUE;
|
||||
|
@ -1238,7 +1291,8 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
|
||||
/* Perform collection on block with the most released sectors.
|
||||
* First mark the block as having no free sectors so we don't
|
||||
* try to move sectors into the block we are trying to erase. */
|
||||
* try to move sectors into the block we are trying to erase.
|
||||
*/
|
||||
|
||||
dev->freecount[collectblock] = 0;
|
||||
|
||||
|
@ -1267,7 +1321,8 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
(CONFIG_SMARTFS_ERASEDSTATE & SMART_STATUS_RELEASED)))
|
||||
{
|
||||
/* This sector doesn't have live data (free or released).
|
||||
* just continue to the next sector and don't move it. */
|
||||
* just continue to the next sector and don't move it.
|
||||
*/
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -1304,27 +1359,35 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
|
||||
/* Commit the sector */
|
||||
|
||||
bytewrite.offset = newsector * dev->mtdBlksPerSector * dev->geo.blocksize +
|
||||
offset = newsector * dev->mtdBlksPerSector * dev->geo.blocksize +
|
||||
offsetof(struct smart_sect_header_s, status);
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
header->status &= ~SMART_STATUS_COMMITTED;
|
||||
newstatus = header->status & ~SMART_STATUS_COMMITTED;
|
||||
#else
|
||||
header->status |= SMART_STATUS_COMMITTED;
|
||||
newstatus = header->status | SMART_STATUS_COMMITTED;
|
||||
#endif
|
||||
bytewrite.count = 1;
|
||||
bytewrite.buffer = &header->status;
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
ret = smart_bytewrite(dev, offset, 1, &newstatus);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d committing new sector %d\n" -ret, newsector);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Release the old physical sector */
|
||||
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
header->status &= ~SMART_STATUS_RELEASED;
|
||||
newstatus = header->status & ~SMART_STATUS_RELEASED;
|
||||
#else
|
||||
header->status |= SMART_STATUS_RELEASED;
|
||||
newstatus = header->status | SMART_STATUS_RELEASED;
|
||||
#endif
|
||||
bytewrite.offset = x * dev->mtdBlksPerSector * dev->geo.blocksize +
|
||||
offset = x * dev->mtdBlksPerSector * dev->geo.blocksize +
|
||||
offsetof(struct smart_sect_header_s, status);
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
ret = smart_bytewrite(dev, offset, 1, &newstatus);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d releasing old sector %d\n" -ret, x);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Update the variables */
|
||||
|
||||
|
@ -1334,17 +1397,7 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
|
||||
/* Now erase the erase block */
|
||||
|
||||
#ifdef CONFIG_MTD_SUBSECTOR_ERASE
|
||||
if (dev->geo.subsectorsize != 0)
|
||||
{
|
||||
/* Perform a sub-sector erase */
|
||||
MTD_IOCTL(dev->mtd, MTDIOC_SECTERASE, collectblock);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
MTD_ERASE(dev->mtd, collectblock, 1);
|
||||
}
|
||||
MTD_ERASE(dev->mtd, collectblock, 1);
|
||||
|
||||
dev->freesectors += dev->releasecount[collectblock];
|
||||
dev->freecount[collectblock] = dev->sectorsPerBlk;
|
||||
|
@ -1357,18 +1410,19 @@ static int smart_garbagecollect(struct smart_struct_s *dev)
|
|||
/* Set the sector size in the 1st header */
|
||||
|
||||
uint8_t sectsize = dev->sectorsize >> 7;
|
||||
header = (struct smart_sect_header_s *) dev->rwbuffer;
|
||||
#if ( CONFIG_SMARTFS_ERASEDSTATE == 0xFF )
|
||||
header->status = (uint8_t) ~SMART_STATUS_SIZEBITS | sectsize;
|
||||
newstatus = (uint8_t) ~SMART_STATUS_SIZEBITS | sectsize;
|
||||
#else
|
||||
header->status = (uint8_t) sectsize;
|
||||
newstatus = (uint8_t) sectsize;
|
||||
#endif
|
||||
/* Write the sector size to the device */
|
||||
|
||||
bytewrite.offset = offsetof(struct smart_sect_header_s, status);
|
||||
bytewrite.count = 1;
|
||||
bytewrite.buffer = &header->status;
|
||||
MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
offset = offsetof(struct smart_sect_header_s, status);
|
||||
ret = smart_bytewrite(dev, offset, 1, &newstatus);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("Error %d setting sector 0 size\n", -ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the block aging information in the format signature sector */
|
||||
|
@ -1402,15 +1456,15 @@ errout:
|
|||
#ifdef CONFIG_FS_WRITABLE
|
||||
static inline int smart_writesector(struct smart_struct_s *dev, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
uint16_t x;
|
||||
bool needsrelocate = FALSE;
|
||||
uint16_t mtdblock;
|
||||
uint16_t physsector;
|
||||
struct smart_read_write_s *req;
|
||||
struct smart_sect_header_s *header;
|
||||
struct mtd_byte_write_s bytewrite;
|
||||
uint8_t byte;
|
||||
int ret;
|
||||
uint16_t x;
|
||||
bool needsrelocate = FALSE;
|
||||
uint16_t mtdblock;
|
||||
uint16_t physsector;
|
||||
struct smart_read_write_s *req;
|
||||
struct smart_sect_header_s *header;
|
||||
size_t offset;
|
||||
uint8_t byte;
|
||||
|
||||
fvdbg("Entry\n");
|
||||
req = (struct smart_read_write_s *) arg;
|
||||
|
@ -1515,16 +1569,14 @@ static inline int smart_writesector(struct smart_struct_s *dev, unsigned long ar
|
|||
/* Commit the new physical sector */
|
||||
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
header->status &= ~SMART_STATUS_COMMITTED;
|
||||
byte = header->status & ~SMART_STATUS_COMMITTED;
|
||||
#else
|
||||
header->status |= SMART_STATUS_COMMITTED;
|
||||
byte = header->status | SMART_STATUS_COMMITTED;
|
||||
#endif
|
||||
bytewrite.offset = physsector * dev->mtdBlksPerSector *
|
||||
dev->geo.blocksize + offsetof(struct smart_sect_header_s, status);
|
||||
bytewrite.count = 1;
|
||||
bytewrite.buffer = (uint8_t *) &header->status;
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
if (ret != OK)
|
||||
offset = physsector * dev->mtdBlksPerSector * dev->geo.blocksize +
|
||||
offsetof(struct smart_sect_header_s, status);
|
||||
ret = smart_bytewrite(dev, offset, 1, &byte);
|
||||
if (ret != 1)
|
||||
{
|
||||
fvdbg("Error committing physical sector %d\n", physsector);
|
||||
ret = -EIO;
|
||||
|
@ -1534,13 +1586,13 @@ static inline int smart_writesector(struct smart_struct_s *dev, unsigned long ar
|
|||
/* Release the old physical sector */
|
||||
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
header->status &= ~SMART_STATUS_RELEASED;
|
||||
byte = header->status & ~SMART_STATUS_RELEASED;
|
||||
#else
|
||||
header->status |= SMART_STATUS_RELEASED;
|
||||
byte = header->status | SMART_STATUS_RELEASED;
|
||||
#endif
|
||||
bytewrite.offset = mtdblock * dev->geo.blocksize +
|
||||
offset = mtdblock * dev->geo.blocksize +
|
||||
offsetof(struct smart_sect_header_s, status);
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
ret = smart_bytewrite(dev, offset, 1, &byte);
|
||||
|
||||
/* Update releasecount for released sector and freecount for the
|
||||
* newly allocated physical sector. */
|
||||
|
@ -1564,11 +1616,9 @@ static inline int smart_writesector(struct smart_struct_s *dev, unsigned long ar
|
|||
/* Not relocated. Just write the portion of the sector that needs
|
||||
* to be written. */
|
||||
|
||||
bytewrite.offset = mtdblock * dev->geo.blocksize +
|
||||
offset = mtdblock * dev->geo.blocksize +
|
||||
sizeof(struct smart_sect_header_s) + req->offset;
|
||||
bytewrite.count = req->count;
|
||||
bytewrite.buffer = req->buffer;
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
ret = smart_bytewrite(dev, offset, req->count, req->buffer);
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
|
@ -1743,9 +1793,8 @@ static inline int smart_allocsector(struct smart_struct_s *dev, unsigned long re
|
|||
* rescan and try again to "self heal" in case of a
|
||||
* bug in our code? */
|
||||
|
||||
fdbg("Couldn't find free sector when I expected too\n");
|
||||
|
||||
/* Unlock the mutex if we add one */
|
||||
fdbg("No free logical sector numbers! Free sectors = %d\n",
|
||||
dev->freesectors);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -1827,7 +1876,7 @@ static inline int smart_freesector(struct smart_struct_s *dev, unsigned long
|
|||
uint16_t physsector;
|
||||
uint16_t block;
|
||||
struct smart_sect_header_s header;
|
||||
struct mtd_byte_write_s bytewrite;
|
||||
size_t offset;
|
||||
|
||||
/* Check if the logical sector is within bounds */
|
||||
|
||||
|
@ -1875,11 +1924,9 @@ static inline int smart_freesector(struct smart_struct_s *dev, unsigned long
|
|||
|
||||
/* Write the status back to the device */
|
||||
|
||||
bytewrite.offset = readaddr + offsetof(struct smart_sect_header_s, status);
|
||||
bytewrite.count = 1;
|
||||
bytewrite.buffer = &header.status;
|
||||
ret = MTD_IOCTL(dev->mtd, MTDIOC_BYTEWRITE, (unsigned long) &bytewrite);
|
||||
if (ret != OK)
|
||||
offset = readaddr + offsetof(struct smart_sect_header_s, status);
|
||||
ret = smart_bytewrite(dev, offset, 1, &header.status);
|
||||
if (ret != 1)
|
||||
{
|
||||
fdbg("Error updating physicl sector %d status\n", physsector);
|
||||
goto errout;
|
||||
|
@ -1900,15 +1947,7 @@ static inline int smart_freesector(struct smart_struct_s *dev, unsigned long
|
|||
{
|
||||
/* Erase the block */
|
||||
|
||||
#ifdef CONFIG_MTD_SUBSECTOR_ERASE
|
||||
if (dev->geo.subsectorsize != 0)
|
||||
{
|
||||
/* Perform a sub-sector erase */
|
||||
MTD_IOCTL(dev->mtd, MTDIOC_SECTERASE, block);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
MTD_ERASE(dev->mtd, block, 1);
|
||||
MTD_ERASE(dev->mtd, block, 1);
|
||||
|
||||
dev->freesectors += dev->releasecount[block];
|
||||
dev->releasecount[block] = 0;
|
||||
|
@ -2050,7 +2089,7 @@ ok_out:
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
int smart_initialize(int minor, FAR struct mtd_dev_s *mtd)
|
||||
int smart_initialize(int minor, FAR struct mtd_dev_s *mtd, const char *partname)
|
||||
{
|
||||
struct smart_struct_s *dev;
|
||||
int ret = -ENOMEM;
|
||||
|
@ -2084,10 +2123,6 @@ int smart_initialize(int minor, FAR struct mtd_dev_s *mtd)
|
|||
|
||||
/* Set these to zero in case the device doesn't support them */
|
||||
|
||||
#ifdef CONFIG_MTD_SUBSECTOR_ERASE
|
||||
dev->geo.subsectorsize= 0;
|
||||
dev->geo.nsubsectors = 0;
|
||||
#endif
|
||||
ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&dev->geo));
|
||||
if (ret < 0)
|
||||
{
|
||||
|
@ -2123,6 +2158,7 @@ int smart_initialize(int minor, FAR struct mtd_dev_s *mtd)
|
|||
|
||||
dev->formatstatus = SMART_FMT_STAT_UNKNOWN;
|
||||
dev->namesize = CONFIG_SMARTFS_MAXNAMLEN;
|
||||
dev->partname = partname;
|
||||
#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS
|
||||
dev->minor = minor;
|
||||
#endif
|
||||
|
@ -2130,7 +2166,10 @@ int smart_initialize(int minor, FAR struct mtd_dev_s *mtd)
|
|||
/* Create a MTD block device name */
|
||||
|
||||
#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS
|
||||
snprintf(dev->rwbuffer, 18, "/dev/smart%dd1", minor);
|
||||
if (partname != NULL)
|
||||
snprintf(dev->rwbuffer, 18, "/dev/smart%d%sd1", minor, partname);
|
||||
else
|
||||
snprintf(dev->rwbuffer, 18, "/dev/smart%dd1", minor);
|
||||
|
||||
/* Inode private data is a reference to a struct containing
|
||||
* the SMART device structure and the root directory number.
|
||||
|
@ -2154,7 +2193,10 @@ int smart_initialize(int minor, FAR struct mtd_dev_s *mtd)
|
|||
ret = register_blockdriver(dev->rwbuffer, &g_bops, 0, rootdirdev);
|
||||
|
||||
#else
|
||||
snprintf(dev->rwbuffer, 18, "/dev/smart%d", minor);
|
||||
if (partname != NULL)
|
||||
snprintf(dev->rwbuffer, 18, "/dev/smart%d%s", minor, partname);
|
||||
else
|
||||
snprintf(dev->rwbuffer, 18, "/dev/smart%d", minor);
|
||||
|
||||
/* Inode private data is a reference to the SMART device structure */
|
||||
|
||||
|
@ -2167,6 +2209,7 @@ int smart_initialize(int minor, FAR struct mtd_dev_s *mtd)
|
|||
kfree(dev->sMap);
|
||||
kfree(dev->rwbuffer);
|
||||
kfree(dev);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Do a scan of the device */
|
||||
|
|
|
@ -389,6 +389,7 @@ static int smartfs_close(FAR struct file *filep)
|
|||
/* Remove ourselves from the linked list */
|
||||
|
||||
nextfile = fs->fs_head;
|
||||
prevfile = nextfile;
|
||||
while ((nextfile != sf) && (nextfile != NULL))
|
||||
{
|
||||
/* Save the previous file pointer too */
|
||||
|
@ -577,7 +578,7 @@ static int smartfs_sync_internal(struct smartfs_mountpt_s *fs,
|
|||
|
||||
if (sf->byteswritten > 0)
|
||||
{
|
||||
fdbg("Syncing sector %d\n", sf->currsector);
|
||||
fvdbg("Syncing sector %d\n", sf->currsector);
|
||||
|
||||
/* Read the existing sector used bytes value */
|
||||
|
||||
|
@ -880,6 +881,7 @@ static off_t smartfs_seek_internal(struct smartfs_mountpt_s *fs,
|
|||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
default:
|
||||
newpos = offset;
|
||||
break;
|
||||
|
||||
|
@ -1034,7 +1036,7 @@ static int smartfs_sync(FAR struct file *filep)
|
|||
struct inode *inode;
|
||||
struct smartfs_mountpt_s *fs;
|
||||
struct smartfs_ofile_s *sf;
|
||||
int ret = OK;
|
||||
int ret;
|
||||
|
||||
/* Sanity checks */
|
||||
|
||||
|
@ -1067,7 +1069,6 @@ static int smartfs_sync(FAR struct file *filep)
|
|||
|
||||
static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp)
|
||||
{
|
||||
FAR struct smart_mountpt_s *fs;
|
||||
struct smartfs_ofile_s *sf;
|
||||
|
||||
fvdbg("Dup %p->%p\n", oldp, newp);
|
||||
|
@ -1080,10 +1081,8 @@ static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp)
|
|||
|
||||
/* Recover our private data from the struct file instance */
|
||||
|
||||
fs = (struct smart_mountpt_s *)oldp->f_inode->i_private;
|
||||
sf = oldp->f_priv;
|
||||
|
||||
DEBUGASSERT(fs != NULL);
|
||||
DEBUGASSERT(sf != NULL);
|
||||
|
||||
/* Just increment the reference count on the ofile */
|
||||
|
|
|
@ -502,6 +502,8 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
|||
|
||||
/* Read the directory */
|
||||
|
||||
offset = 0xFFFF;
|
||||
|
||||
#if CONFIG_SMARTFS_ERASEDSTATE == 0xFF
|
||||
while (dirsector != 0xFFFF)
|
||||
#else
|
||||
|
@ -549,7 +551,8 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
|||
|
||||
/* Test if the name matches */
|
||||
|
||||
if (strcmp(entry->name, fs->fs_workbuffer) == 0)
|
||||
if (strncmp(entry->name, fs->fs_workbuffer,
|
||||
fs->fs_llformat.namesize) == 0)
|
||||
{
|
||||
/* We found it! If this is the last segment entry,
|
||||
* then report the entry. If it isn't the last
|
||||
|
@ -571,10 +574,11 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
|
|||
direntry->dfirst = dirstack[depth];
|
||||
if (direntry->name == NULL)
|
||||
{
|
||||
direntry->name = (char *) kmalloc(fs->fs_llformat.namesize);
|
||||
direntry->name = (char *) kmalloc(fs->fs_llformat.namesize+1);
|
||||
}
|
||||
|
||||
strcpy(direntry->name, entry->name);
|
||||
memset(direntry->name, 0, fs->fs_llformat.namesize + 1);
|
||||
strncpy(direntry->name, entry->name, fs->fs_llformat.namesize);
|
||||
direntry->datlen = 0;
|
||||
|
||||
/* Scan the file's sectors to calculate the length and perform
|
||||
|
@ -734,7 +738,7 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
|||
|
||||
/* Validate the name isn't too long */
|
||||
|
||||
if (strlen(filename) + 1 > fs->fs_llformat.namesize)
|
||||
if (strlen(filename) > fs->fs_llformat.namesize)
|
||||
{
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
@ -887,13 +891,13 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
|||
entry->firstsector = nextsector;
|
||||
entry->utc = 0;
|
||||
memset(entry->name, 0, fs->fs_llformat.namesize);
|
||||
strncpy(entry->name, filename, fs->fs_llformat.namesize-1);
|
||||
strncpy(entry->name, filename, fs->fs_llformat.namesize);
|
||||
|
||||
/* Now write the new entry to the parent directory sector */
|
||||
|
||||
readwrite.logsector = psector;
|
||||
readwrite.offset = offset;
|
||||
readwrite.count = sizeof(struct smartfs_entry_header_s) + fs->fs_llformat.namesize;
|
||||
readwrite.count = entrysize;
|
||||
readwrite.buffer = (uint8_t *) &fs->fs_rwbuffer[offset];
|
||||
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
|
||||
if (ret < 0)
|
||||
|
@ -911,11 +915,11 @@ int smartfs_createentry(struct smartfs_mountpt_s *fs,
|
|||
direntry->datlen = 0;
|
||||
if (direntry->name == NULL)
|
||||
{
|
||||
direntry->name = (FAR char *) kmalloc(fs->fs_llformat.namesize);
|
||||
direntry->name = (FAR char *) kmalloc(fs->fs_llformat.namesize+1);
|
||||
}
|
||||
|
||||
memset(direntry->name, 0, fs->fs_llformat.namesize);
|
||||
strncpy(direntry->name, filename, fs->fs_llformat.namesize-1);
|
||||
memset(direntry->name, 0, fs->fs_llformat.namesize+1);
|
||||
strncpy(direntry->name, filename, fs->fs_llformat.namesize);
|
||||
|
||||
ret = OK;
|
||||
|
||||
|
|
|
@ -193,15 +193,6 @@
|
|||
* of device memory */
|
||||
#define MTDIOC_BULKERASE _MTDIOC(0x0003) /* IN: None
|
||||
* OUT: None */
|
||||
#define MTDIOC_GETCAPS _MTDIOC(0x0004) /* IN: None
|
||||
* OUT: Capabilities flags */
|
||||
#define MTDIOC_SECTERASE _MTDIOC(0x0005) /* IN: Sector number to erase
|
||||
* OUT: None */
|
||||
#define MTDIOC_BYTEWRITE _MTDIOC(0x0006) /* IN: Pointer to bytewrite structure
|
||||
* OUT: None */
|
||||
|
||||
#define MTDIOC_CAPS_SECTERASE 0x01
|
||||
#define MTDIOC_CAPS_BYTEWRITE 0x02
|
||||
|
||||
/* NuttX ARP driver ioctl definitions (see netinet/arp.h) *******************/
|
||||
|
||||
|
|
|
@ -83,10 +83,6 @@ struct mtd_geometry_s
|
|||
uint16_t erasesize; /* Size of one erase blocks -- must be a multiple
|
||||
* of blocksize. */
|
||||
size_t neraseblocks; /* Number of erase blocks */
|
||||
#ifdef CONFIG_MTD_SUBSECTOR_ERASE
|
||||
uint16_t subsectorsize; /* Size of the sub-sector erase block */
|
||||
uint16_t nsubsectors; /* Number of sub-sector erase blocks */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The following defines the information for writing bytes to a sector
|
||||
|
@ -179,8 +175,8 @@ extern "C"
|
|||
* NOTE: Since there may be a number of MTD partition drivers operating on
|
||||
* the same, underlying FLASH driver, that FLASH driver must be capable
|
||||
* of enforcing mutually exclusive access to the FLASH device. Without
|
||||
* paritions, that mutual exclusing would be provided by the file system
|
||||
* abover the FLASH driver.
|
||||
* partitions, that mutual exclusion would be provided by the file system
|
||||
* above the FLASH driver.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -213,10 +209,13 @@ int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd);
|
|||
* minor - The minor device number. The MTD block device will be
|
||||
* registered as as /dev/mtdsmartN where N is the minor number.
|
||||
* mtd - The MTD device that supports the FLASH interface.
|
||||
* partname - Optional partition name to append to dev entry, NULL if
|
||||
* not supplied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int smart_initialize(int minor, FAR struct mtd_dev_s *mtd);
|
||||
int smart_initialize(int minor, FAR struct mtd_dev_s *mtd,
|
||||
FAR const char *partname);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: flash_eraseall
|
||||
|
|
|
@ -2368,7 +2368,8 @@ static char *parse_kconfigfile(FILE *stream, const char *kconfigdir)
|
|||
{
|
||||
/* Set token to NULL to skip to the next line */
|
||||
|
||||
error("Unhandled token: %s\n", token);
|
||||
error("File %s/Kconfig Unhandled token: %s\n",
|
||||
kconfigdir, token);
|
||||
token = NULL;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue