This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 28739b8b8a libc/stream:Add mtd backend stream. 28739b8b8a is described below commit 28739b8b8abeab88d2371f5b49d85899a1029045 Author: 田昕 <tianx...@xiaomi.com> AuthorDate: Wed Nov 23 11:02:38 2022 +0800 libc/stream:Add mtd backend stream. Signed-off-by: 田昕 <tianx...@xiaomi.com> --- arch/risc-v/src/esp32c3/esp32c3_spiflash_mtd.c | 90 ++------ include/nuttx/streams.h | 53 +++++ libs/libc/stream/Make.defs | 2 +- libs/libc/stream/lib_mtdoutstream.c | 301 +++++++++++++++++++++++++ 4 files changed, 379 insertions(+), 67 deletions(-) diff --git a/arch/risc-v/src/esp32c3/esp32c3_spiflash_mtd.c b/arch/risc-v/src/esp32c3/esp32c3_spiflash_mtd.c index 7573d38a44..02ac929a15 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_spiflash_mtd.c +++ b/arch/risc-v/src/esp32c3/esp32c3_spiflash_mtd.c @@ -139,10 +139,6 @@ static const struct esp32c3_mtd_dev_s g_esp32c3_spiflash_encrypt = } }; -/* Ensure exclusive access to the driver */ - -static mutex_t g_lock = NXMUTEX_INITIALIZER; - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -170,6 +166,7 @@ static int esp32c3_erase(struct mtd_dev_s *dev, off_t startblock, uint32_t offset = startblock * MTD_ERASE_SIZE; uint32_t nbytes = nblocks * MTD_ERASE_SIZE; struct esp32c3_mtd_dev_s *priv = (struct esp32c3_mtd_dev_s *)dev; + irqstate_t flags; if ((offset > MTD_SIZE(priv)) || ((offset + nbytes) > MTD_SIZE(priv))) { @@ -182,14 +179,9 @@ static int esp32c3_erase(struct mtd_dev_s *dev, off_t startblock, finfo("spi_flash_erase_range(0x%x, %d)\n", offset, nbytes); #endif - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_erase_range(offset, nbytes); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -231,6 +223,7 @@ static ssize_t esp32c3_read(struct mtd_dev_s *dev, off_t offset, size_t nbytes, uint8_t *buffer) { ssize_t ret; + irqstate_t flags; #ifdef CONFIG_ESP32C3_STORAGE_MTD_DEBUG finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer); @@ -238,16 +231,9 @@ static ssize_t esp32c3_read(struct mtd_dev_s *dev, off_t offset, finfo("spi_flash_read(0x%x, %p, %d)\n", offset, buffer, nbytes); #endif - /* Acquire the mutex. */ - - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_read(offset, buffer, nbytes); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -284,6 +270,7 @@ static ssize_t esp32c3_bread(struct mtd_dev_s *dev, off_t startblock, ssize_t ret; uint32_t addr = startblock * MTD_BLK_SIZE; uint32_t size = nblocks * MTD_BLK_SIZE; + irqstate_t flags; #ifdef CONFIG_ESP32C3_STORAGE_MTD_DEBUG finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, nblocks, @@ -292,14 +279,9 @@ static ssize_t esp32c3_bread(struct mtd_dev_s *dev, off_t startblock, finfo("spi_flash_read(0x%x, %p, %d)\n", addr, buffer, size); #endif - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_read(addr, buffer, size); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -337,6 +319,7 @@ static ssize_t esp32c3_read_decrypt(struct mtd_dev_s *dev, uint8_t *buffer) { ssize_t ret; + irqstate_t flags; #ifdef CONFIG_ESP32C3_STORAGE_MTD_DEBUG finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer); @@ -345,16 +328,9 @@ static ssize_t esp32c3_read_decrypt(struct mtd_dev_s *dev, nbytes); #endif - /* Acquire the mutex. */ - - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_read_encrypted(offset, buffer, nbytes); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -393,6 +369,7 @@ static ssize_t esp32c3_bread_decrypt(struct mtd_dev_s *dev, ssize_t ret; uint32_t addr = startblock * MTD_BLK_SIZE; uint32_t size = nblocks * MTD_BLK_SIZE; + irqstate_t flags; #ifdef CONFIG_ESP32C3_STORAGE_MTD_DEBUG finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, nblocks, @@ -401,14 +378,9 @@ static ssize_t esp32c3_bread_decrypt(struct mtd_dev_s *dev, finfo("spi_flash_read_encrypted(0x%x, %p, %d)\n", addr, buffer, size); #endif - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_read_encrypted(addr, buffer, size); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -444,6 +416,7 @@ static ssize_t esp32c3_write(struct mtd_dev_s *dev, off_t offset, { ssize_t ret; struct esp32c3_mtd_dev_s *priv = (struct esp32c3_mtd_dev_s *)dev; + irqstate_t flags; ASSERT(buffer); @@ -458,16 +431,9 @@ static ssize_t esp32c3_write(struct mtd_dev_s *dev, off_t offset, finfo("spi_flash_write(0x%x, %p, %d)\n", offset, buffer, nbytes); #endif - /* Acquire the mutex. */ - - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_write(offset, buffer, nbytes); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -505,6 +471,7 @@ static ssize_t esp32c3_bwrite(struct mtd_dev_s *dev, off_t startblock, ssize_t ret; uint32_t addr = startblock * MTD_BLK_SIZE; uint32_t size = nblocks * MTD_BLK_SIZE; + irqstate_t flags; #ifdef CONFIG_ESP32C3_STORAGE_MTD_DEBUG finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, @@ -513,14 +480,9 @@ static ssize_t esp32c3_bwrite(struct mtd_dev_s *dev, off_t startblock, finfo("spi_flash_write(0x%x, %p, %d)\n", addr, buffer, size); #endif - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_write(addr, buffer, size); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { @@ -560,6 +522,7 @@ static ssize_t esp32c3_bwrite_encrypt(struct mtd_dev_s *dev, ssize_t ret; uint32_t addr = startblock * MTD_BLK_SIZE; uint32_t size = nblocks * MTD_BLK_SIZE; + irqstate_t flags; #ifdef CONFIG_ESP32C3_STORAGE_MTD_DEBUG finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, @@ -568,14 +531,9 @@ static ssize_t esp32c3_bwrite_encrypt(struct mtd_dev_s *dev, finfo("spi_flash_write_encrypted(0x%x, %p, %d)\n", addr, buffer, size); #endif - ret = nxmutex_lock(&g_lock); - if (ret < 0) - { - return ret; - } - + flags = enter_critical_section(); ret = spi_flash_write_encrypted(addr, buffer, size); - nxmutex_unlock(&g_lock); + leave_critical_section(flags); if (ret == OK) { diff --git a/include/nuttx/streams.h b/include/nuttx/streams.h index 98348019f3..4077a3ecf0 100644 --- a/include/nuttx/streams.h +++ b/include/nuttx/streams.h @@ -31,6 +31,9 @@ #include <stdio.h> #ifndef CONFIG_DISABLE_MOUNTPOINT #include <nuttx/fs/fs.h> +#ifdef CONFIG_MTD +#include <nuttx/mtd/mtd.h> +#endif #endif /**************************************************************************** @@ -210,6 +213,16 @@ struct lib_blkoutstream_s }; #endif +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD) +struct lib_mtdoutstream_s +{ + struct lib_outstream_s public; + FAR struct inode *inode; + struct mtd_geometry_s geo; + FAR unsigned char *cache; +}; +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -427,6 +440,46 @@ int lib_blkoutstream_open(FAR struct lib_blkoutstream_s *stream, void lib_blkoutstream_close(FAR struct lib_blkoutstream_s *stream); #endif +/**************************************************************************** + * Name: lib_mtdoutstream_open + * + * Description: + * mtd driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_mtdoutstream_s to be initialized. + * name - The full path of mtd device. + * + * Returned Value: + * Returns zero on success or a negated errno on failure + * + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD) +int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream, + FAR const char *name); +#endif + +/**************************************************************************** + * Name: lib_mtdoutstream_close + * + * Description: + * close mtd driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_mtdoutstream_s to be initialized. + * + * Returned Value: + * None (User allocated instance initialized). + * + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD) +void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream); +#endif + /**************************************************************************** * Name: lib_noflush * diff --git a/libs/libc/stream/Make.defs b/libs/libc/stream/Make.defs index 622b3f1f67..f7cddfde39 100644 --- a/libs/libc/stream/Make.defs +++ b/libs/libc/stream/Make.defs @@ -25,7 +25,7 @@ CSRCS += lib_meminstream.c lib_memoutstream.c lib_memsistream.c CSRCS += lib_memsostream.c lib_lowoutstream.c lib_rawinstream.c CSRCS += lib_rawoutstream.c lib_rawsistream.c lib_rawsostream.c CSRCS += lib_zeroinstream.c lib_nullinstream.c lib_nulloutstream.c -CSRCS += lib_libnoflush.c lib_libsnoflush.c +CSRCS += lib_mtdoutstream.c lib_libnoflush.c lib_libsnoflush.c # The remaining sources files depend upon C streams diff --git a/libs/libc/stream/lib_mtdoutstream.c b/libs/libc/stream/lib_mtdoutstream.c new file mode 100644 index 0000000000..ac0d037b75 --- /dev/null +++ b/libs/libc/stream/lib_mtdoutstream.c @@ -0,0 +1,301 @@ +/**************************************************************************** + * libs/libc/stream/lib_mtdoutstream.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <unistd.h> +#include <nuttx/streams.h> +#include <nuttx/fs/fs.h> +#include <nuttx/mtd/mtd.h> + +#include "libc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mtdoutstream_flush + ****************************************************************************/ + +static int mtdoutstream_flush(FAR struct lib_outstream_s *this) +{ + FAR struct lib_mtdoutstream_s *stream = + (FAR struct lib_mtdoutstream_s *)this; + size_t erasesize = stream->geo.erasesize; + size_t nblkpererase = erasesize / stream->geo.blocksize; + int ret = OK; + + if (this->nput % erasesize > 0) + { +#ifdef CONFIG_MTD_BYTE_WRITE + /* if byte write, flush won't be needed */ + + if (stream->inode->u.i_mtd->write == NULL) +#endif + { + ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1); + if (ret < 0) + { + return ret; + } + + ret = MTD_BWRITE(stream->inode->u.i_mtd, + this->nput / erasesize * nblkpererase, + nblkpererase, stream->cache); + } + } + + return ret; +} + +/**************************************************************************** + * Name: mtdoutstream_puts + ****************************************************************************/ + +static int mtdoutstream_puts(FAR struct lib_outstream_s *this, + FAR const void *buf, int len) +{ + FAR struct lib_mtdoutstream_s *stream = + (FAR struct lib_mtdoutstream_s *)this; + size_t erasesize = stream->geo.erasesize; + size_t nblkpererase = erasesize / stream->geo.blocksize; + FAR struct inode *inode = stream->inode; + FAR const unsigned char *ptr = buf; + size_t remain = len; + int ret; + + if (this->nput + len > erasesize * stream->geo.neraseblocks) + { + return -ENOSPC; + } + +#ifdef CONFIG_MTD_BYTE_WRITE + if (stream->inode->u.i_mtd->write != NULL) + { + if (this->nput % stream->geo.erasesize == 0) + { + ret = MTD_ERASE(inode->u.i_mtd, + this->nput / stream->geo.erasesize, 1); + if (ret < 0) + { + return ret; + } + } + + ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf); + if (ret < 0) + { + return ret; + } + + this->nput += len; + } + else +#endif + { + while (remain > 0) + { + size_t sblock = this->nput / erasesize; + size_t offset = this->nput % erasesize; + + if (offset > 0) + { + size_t copyin = offset + remain > erasesize ? + erasesize - offset : remain; + + memcpy(stream->cache + offset, ptr, copyin); + + ptr += copyin; + offset += copyin; + this->nput += copyin; + remain -= copyin; + + if (offset == erasesize) + { + ret = MTD_ERASE(inode->u.i_mtd, sblock, 1); + if (ret < 0) + { + return ret; + } + + ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblkpererase, + nblkpererase, stream->cache); + if (ret < 0) + { + return ret; + } + } + } + else if (remain < erasesize) + { + /* erase content to all 0 before caching, + * so no random content will be flushed + */ + + memset(stream->cache, 0, stream->geo.erasesize); + memcpy(stream->cache, ptr, remain); + this->nput += remain; + remain = 0; + } + else if (remain >= erasesize) + { + size_t copyin = (remain / erasesize) * erasesize; + + ret = MTD_ERASE(inode->u.i_mtd, sblock, + remain / erasesize); + if (ret < 0) + { + return ret; + } + + ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblkpererase, + remain / erasesize * nblkpererase, + ptr); + if (ret < 0) + { + return ret; + } + + ptr += copyin; + this->nput += copyin; + remain -= copyin; + } + } + } + + return len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_mtdoutstream_close + * + * Description: + * close mtd driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_mtdoutstream_s to be initialized. + * + * Returned Value: + * None (User allocated instance initialized). + * + ****************************************************************************/ + +void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream) +{ + if (stream != NULL) + { + if (stream->inode != NULL) + { + close_mtddriver(stream->inode); + stream->inode = NULL; + } + + if (stream->cache != NULL) + { + lib_free(stream->cache); + stream->cache = NULL; + } + } +} + +/**************************************************************************** + * Name: lib_mtdoutstream_open + * + * Description: + * mtd driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_mtdoutstream_s to be initialized. + * name - The full path of mtd device. + * + * Returned Value: + * Returns zero on success or a negated errno on failure + * + ****************************************************************************/ + +int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream, + FAR const char *name) +{ + FAR struct inode *node = NULL; + int ret; + + if (stream == NULL || name == NULL) + { + return -EINVAL; + } + + ret = find_mtddriver(name, &node); + if (ret < 0) + { + return ret; + } + + memset(stream, 0, sizeof(*stream)); + + if (node->u.i_mtd->ioctl == NULL || + node->u.i_mtd->erase == NULL || + node->u.i_mtd->bwrite == NULL || + node->u.i_mtd->ioctl(node->u.i_mtd, MTDIOC_GEOMETRY, + (unsigned long)&stream->geo) < 0 || + stream->geo.blocksize <= 0 || + stream->geo.erasesize <= 0 || + stream->geo.neraseblocks <= 0) + { + close_mtddriver(node); + return -EINVAL; + } + +#ifdef CONFIG_MTD_BYTE_WRITE + if (node->u.i_mtd->write == NULL) +#endif + { + stream->cache = lib_zalloc(stream->geo.erasesize); + if (stream->cache == NULL) + { + close_mtddriver(node); + return -ENOMEM; + } + } + + stream->inode = node; + stream->public.puts = mtdoutstream_puts; + stream->public.flush = mtdoutstream_flush; + + return OK; +} + +#endif /* CONFIG_MTD */