diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2013-05-03 12:52:33 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2013-05-03 12:52:33 -0600 |
commit | 1092e4b16395d945517b9bcbc2c48828fbe9303c (patch) | |
tree | e2171ab3f21ae1e0610903694901c776a7e1a1d8 | |
parent | 2567deb0338a774086231fbb778b639c10398cc1 (diff) | |
download | px4-nuttx-1092e4b16395d945517b9bcbc2c48828fbe9303c.tar.gz px4-nuttx-1092e4b16395d945517b9bcbc2c48828fbe9303c.tar.bz2 px4-nuttx-1092e4b16395d945517b9bcbc2c48828fbe9303c.zip |
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).
28 files changed, 1819 insertions, 456 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 753bdc5cc..d6971dc45 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -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). diff --git a/apps/examples/Kconfig b/apps/examples/Kconfig index b1c7e7793..11a56a81c 100644 --- a/apps/examples/Kconfig +++ b/apps/examples/Kconfig @@ -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" diff --git a/apps/examples/Make.defs b/apps/examples/Make.defs index eb2b5ed87..67b07a21b 100644 --- a/apps/examples/Make.defs +++ b/apps/examples/Make.defs @@ -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 diff --git a/apps/examples/Makefile b/apps/examples/Makefile index 41593b8f9..a10fef5dc 100644 --- a/apps/examples/Makefile +++ b/apps/examples/Makefile @@ -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 diff --git a/apps/examples/README.txt b/apps/examples/README.txt index ec9685f4e..24afaf699 100644 --- a/apps/examples/README.txt +++ b/apps/examples/README.txt @@ -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 ^^^^^^^^^^^^^^^^^^^ diff --git a/apps/examples/mtdpart/Kconfig b/apps/examples/mtdpart/Kconfig index 363b6091f..6f8e6e490 100644 --- a/apps/examples/mtdpart/Kconfig +++ b/apps/examples/mtdpart/Kconfig @@ -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 diff --git a/apps/examples/smart/.gitignore b/apps/examples/smart/.gitignore new file mode 100644 index 000000000..3c8fd3435 --- /dev/null +++ b/apps/examples/smart/.gitignore @@ -0,0 +1,12 @@ +Make.dep +.depend +.built +*.swp +*.asm +*.rel +*.lst +*.sym +*.adb +*.lib +*.src + diff --git a/apps/examples/smart/Kconfig b/apps/examples/smart/Kconfig new file mode 100644 index 000000000..933b33913 --- /dev/null +++ b/apps/examples/smart/Kconfig @@ -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 diff --git a/apps/examples/smart/Makefile b/apps/examples/smart/Makefile new file mode 100644 index 000000000..60614ca5d --- /dev/null +++ b/apps/examples/smart/Makefile @@ -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 diff --git a/apps/examples/smart/smart_main.c b/apps/examples/smart/smart_main.c new file mode 100644 index 000000000..ce303caa7 --- /dev/null +++ b/apps/examples/smart/smart_main.c @@ -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; +} + diff --git a/apps/examples/smart_test/smart_test.c b/apps/examples/smart_test/smart_test.c index 3f8e42449..efce1b0bf 100644 --- a/apps/examples/smart_test/smart_test.c +++ b/apps/examples/smart_test/smart_test.c @@ -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 diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 8b8c3152d..1d10872fc 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -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). diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html index f758564ea..322667449 100644 --- a/nuttx/Documentation/NuttX.html +++ b/nuttx/Documentation/NuttX.html @@ -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> @@ -2571,6 +2584,38 @@ nsh> <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> + <p> <b>STMicro STM32 F427/437</b>. General architectural support was provided for the F427/437 family in NuttX 4.27. Specific support includes the STM32F427I, STM32F427Z, and STM32F427V chips. diff --git a/nuttx/configs/mikroe-stm32f4/Kconfig b/nuttx/configs/mikroe-stm32f4/Kconfig index 8e55f0d17..0790f123a 100644 --- a/nuttx/configs/mikroe-stm32f4/Kconfig +++ b/nuttx/configs/mikroe-stm32f4/Kconfig @@ -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--- + 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--- - The activity weight to report to the power management subsystem when a button is pressed. + 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 diff --git a/nuttx/configs/mikroe-stm32f4/README.txt b/nuttx/configs/mikroe-stm32f4/README.txt index ed4ecbf2c..7d46fbc5c 100644 --- a/nuttx/configs/mikroe-stm32f4/README.txt +++ b/nuttx/configs/mikroe-stm32f4/README.txt @@ -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 ======== diff --git a/nuttx/configs/mikroe-stm32f4/src/up_nsh.c b/nuttx/configs/mikroe-stm32f4/src/up_nsh.c index e92a02e83..226a715f6 100644 --- a/nuttx/configs/mikroe-stm32f4/src/up_nsh.c +++ b/nuttx/configs/mikroe-stm32f4/src/up_nsh.c @@ -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 */ diff --git a/nuttx/configs/mikroe-stm32f4/usbnsh/defconfig b/nuttx/configs/mikroe-stm32f4/usbnsh/defconfig index 29e948be5..3340a95e6 100644 --- a/nuttx/configs/mikroe-stm32f4/usbnsh/defconfig +++ b/nuttx/configs/mikroe-stm32f4/usbnsh/defconfig @@ -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 diff --git a/nuttx/configs/stm32f4discovery/README.txt b/nuttx/configs/stm32f4discovery/README.txt index f5a261410..684c916f5 100644 --- a/nuttx/configs/stm32f4discovery/README.txt +++ b/nuttx/configs/stm32f4discovery/README.txt @@ -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 ======== diff --git a/nuttx/drivers/mtd/Kconfig b/nuttx/drivers/mtd/Kconfig index 310f494d8..4754fbeb7 100644 --- a/nuttx/drivers/mtd/Kconfig +++ b/nuttx/drivers/mtd/Kconfig @@ -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 diff --git a/nuttx/drivers/mtd/m25px.c b/nuttx/drivers/mtd/m25px.c index bfe21a7dd..17f7a0672 100644 --- a/nuttx/drivers/mtd/m25px.c +++ b/nuttx/drivers/mtd/m25px.c @@ -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,55 +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 */ - - (void)SPI_SEND(priv->dev, M25P_SE); - - /* 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"); -} - -/************************************************************************************ - * 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. + /* Send the "Sector Erase (SE)" or Sub-Sector Erase (SSE) instruction + * that was passed in as the erase type. */ - 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); + (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 @@ -566,7 +535,6 @@ static inline void m25p_subsectorerase(struct m25p_dev_s *priv, off_t subsector) 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; + + /* 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; - m25p_sectorerase(priv, startblock); + /* 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; } @@ -818,6 +829,78 @@ static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t 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; diff --git a/nuttx/drivers/mtd/mtd_partition.c b/nuttx/drivers/mtd/mtd_partition.c index 1bff0af9c..699a2fa5a 100644 --- a/nuttx/drivers/mtd/mtd_partition.c +++ b/nuttx/drivers/mtd/mtd_partition.c @@ -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; diff --git a/nuttx/drivers/mtd/rammtd.c b/nuttx/drivers/mtd/rammtd.c index 461cd7d99..137f91f73 100644 --- a/nuttx/drivers/mtd/rammtd.c +++ b/nuttx/drivers/mtd/rammtd.c @@ -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) { @@ -329,6 +329,34 @@ static ssize_t ram_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, } /**************************************************************************** + * 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; diff --git a/nuttx/drivers/mtd/smart.c b/nuttx/drivers/mtd/smart.c index 9de557b5f..35a367e5b 100644 --- a/nuttx/drivers/mtd/smart.c +++ b/nuttx/drivers/mtd/smart.c @@ -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; @@ -569,6 +542,74 @@ static int smart_setsectorsize(struct smart_struct_s *dev, uint16_t size) } /**************************************************************************** + * 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 * * Description: Performs a scan of the MTD device searching for format @@ -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 */ diff --git a/nuttx/fs/smartfs/smartfs_smart.c b/nuttx/fs/smartfs/smartfs_smart.c index 552c0e96e..a1613b899 100644 --- a/nuttx/fs/smartfs/smartfs_smart.c +++ b/nuttx/fs/smartfs/smartfs_smart.c @@ -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 */ diff --git a/nuttx/fs/smartfs/smartfs_utils.c b/nuttx/fs/smartfs/smartfs_utils.c index a72fef691..30813a44b 100644 --- a/nuttx/fs/smartfs/smartfs_utils.c +++ b/nuttx/fs/smartfs/smartfs_utils.c @@ -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; diff --git a/nuttx/include/nuttx/fs/ioctl.h b/nuttx/include/nuttx/fs/ioctl.h index 463b96e18..bd80a7150 100644 --- a/nuttx/include/nuttx/fs/ioctl.h +++ b/nuttx/include/nuttx/fs/ioctl.h @@ -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) *******************/ diff --git a/nuttx/include/nuttx/mtd.h b/nuttx/include/nuttx/mtd.h index c4bf4fbee..a528d0003 100644 --- a/nuttx/include/nuttx/mtd.h +++ b/nuttx/include/nuttx/mtd.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 diff --git a/nuttx/tools/kconfig2html.c b/nuttx/tools/kconfig2html.c index f6d21091a..9a089c415 100644 --- a/nuttx/tools/kconfig2html.c +++ b/nuttx/tools/kconfig2html.c @@ -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; |