diff --git a/include/nuttx/streams.h b/include/nuttx/streams.h index 4d531142113..98348019f38 100644 --- a/include/nuttx/streams.h +++ b/include/nuttx/streams.h @@ -29,6 +29,9 @@ #include #include +#ifndef CONFIG_DISABLE_MOUNTPOINT +#include +#endif /**************************************************************************** * Pre-processor Definitions @@ -197,6 +200,16 @@ struct lib_lzfoutstream_s }; #endif +#ifndef CONFIG_DISABLE_MOUNTPOINT +struct lib_blkoutstream_s +{ + struct lib_outstream_s public; + FAR struct inode *inode; + struct geometry geo; + FAR unsigned char *cache; +}; +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -374,6 +387,46 @@ void lib_lzfoutstream(FAR struct lib_lzfoutstream_s *stream, FAR struct lib_outstream_s *backend); #endif +/**************************************************************************** + * Name: lib_blkoutstream_open + * + * Description: + * open block driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_blkoutstream_s to be initialized. + * name - The full path to the block driver to be opened. + * + * Returned Value: + * Returns zero on success or a negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +int lib_blkoutstream_open(FAR struct lib_blkoutstream_s *stream, + FAR const char *name); +#endif + +/**************************************************************************** + * Name: lib_blkoutstream_close + * + * Description: + * close block driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_blkoutstream_s to be initialized. + * + * Returned Value: + * None (User allocated instance initialized). + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +void lib_blkoutstream_close(FAR struct lib_blkoutstream_s *stream); +#endif + /**************************************************************************** * Name: lib_noflush * diff --git a/libs/libc/stream/Make.defs b/libs/libc/stream/Make.defs index 7af465dc095..622b3f1f67b 100644 --- a/libs/libc/stream/Make.defs +++ b/libs/libc/stream/Make.defs @@ -38,6 +38,10 @@ ifeq ($(CONFIG_LIBC_LZF),y) CSRCS += lib_lzfcompress.c endif +ifeq ($(CONFIG_DISABLE_MOUNTPOINT),) +CSRCS += lib_blkoutstream.c +endif + # Add the stdio directory to the build DEPPATH += --dep-path stream diff --git a/libs/libc/stream/lib_blkoutstream.c b/libs/libc/stream/lib_blkoutstream.c new file mode 100644 index 00000000000..929cb1997ee --- /dev/null +++ b/libs/libc/stream/lib_blkoutstream.c @@ -0,0 +1,225 @@ +/**************************************************************************** + * libs/libc/stream/lib_blkoutstream.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 + +#include +#include + +#include "libc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: blkoutstream_flush + ****************************************************************************/ + +static int blkoutstream_flush(FAR struct lib_outstream_s *this) +{ + FAR struct lib_blkoutstream_s *stream = + (FAR struct lib_blkoutstream_s *)this; + size_t sectorsize = stream->geo.geo_sectorsize; + int ret = OK; + + if (this->nput % sectorsize > 0) + { + ret = stream->inode->u.i_bops->write(stream->inode, stream->cache, + this->nput / sectorsize, 1); + } + + return ret; +} + +/**************************************************************************** + * Name: blkoutstream_puts + ****************************************************************************/ + +static int blkoutstream_puts(FAR struct lib_outstream_s *this, + FAR const void *buf, int len) +{ + FAR struct lib_blkoutstream_s *stream = + (FAR struct lib_blkoutstream_s *)this; + size_t sectorsize = stream->geo.geo_sectorsize; + FAR struct inode *inode = stream->inode; + FAR const unsigned char *ptr = buf; + size_t remain = len; + int ret; + + while (remain > 0) + { + size_t sblock = this->nput / sectorsize; + size_t offset = this->nput % sectorsize; + + if (offset > 0) + { + size_t copyin = offset + remain > sectorsize ? + sectorsize - offset : remain; + + memcpy(stream->cache + offset, ptr, copyin); + + ptr += copyin; + offset += copyin; + this->nput += copyin; + remain -= copyin; + + if (offset == stream->geo.geo_sectorsize) + { + ret = inode->u.i_bops->write(inode, stream->cache, sblock, 1); + if (ret < 0) + { + return ret; + } + } + } + else if (remain < stream->geo.geo_sectorsize) + { + memcpy(stream->cache, ptr, remain); + this->nput += remain; + remain = 0; + } + else if (remain >= stream->geo.geo_sectorsize) + { + size_t copyin = (remain / stream->geo.geo_sectorsize) * + stream->geo.geo_sectorsize; + + ret = inode->u.i_bops->write(inode, ptr, sblock, + remain / stream->geo.geo_sectorsize); + if (ret < 0) + { + return ret; + } + + ptr += copyin; + this->nput += copyin; + remain -= copyin; + } + } + + return len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_blkoutstream_close + * + * Description: + * close block driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_blkoutstream_s to be initialized. + * + * Returned Value: + * None (User allocated instance initialized). + * + ****************************************************************************/ + +void lib_blkoutstream_close(FAR struct lib_blkoutstream_s *stream) +{ + if (stream) + { + if (stream->inode) + { + close_blockdriver(stream->inode); + stream->inode = NULL; + } + + if (stream->cache) + { + lib_free(stream->cache); + stream->cache = NULL; + } + } +} + +/**************************************************************************** + * Name: lib_blkoutstream_open + * + * Description: + * block driver stream backend + * + * Input Parameters: + * stream - User allocated, uninitialized instance of struct + * lib_blkoutstream_s to be initialized. + * name - The full path to the block driver to be opened. + * + * Returned Value: + * Returns zero on success or a negated errno on failure + * + ****************************************************************************/ + +int lib_blkoutstream_open(FAR struct lib_blkoutstream_s *stream, + FAR const char *name) +{ + FAR struct inode *inode = NULL; + int ret; + + if (stream == NULL || name == NULL) + { + return -EINVAL; + } + + ret = open_blockdriver(name, 0, &inode); + if (ret < 0) + { + return ret; + } + + memset(stream, 0, sizeof(*stream)); + + if (inode->u.i_bops->geometry == NULL || + inode->u.i_bops->write == NULL || + inode->u.i_bops->geometry(inode, &stream->geo) < 0 || + stream->geo.geo_sectorsize <= 0 || + stream->geo.geo_nsectors <= 0) + { + close_blockdriver(inode); + return -EINVAL; + } + + stream->cache = lib_malloc(stream->geo.geo_sectorsize); + if (stream->cache == NULL) + { + close_blockdriver(inode); + return -ENOMEM; + } + + stream->inode = inode; + stream->public.puts = blkoutstream_puts; + stream->public.flush = blkoutstream_flush; + + return OK; +} +#endif