[PATCH 1/2] dev/flash: Add API for Flash devices
aaron.nyholm at unfoldedeffective.com
aaron.nyholm at unfoldedeffective.com
Thu Mar 16 02:56:26 UTC 2023
From: Aaron Nyholm <aaron.nyholm at southerninnovation.com>
Updates #4896
---
cpukit/dev/flash/flashdev.c | 353 ++++++++++++++++++++++++++++
cpukit/include/dev/flash/flashdev.h | 95 ++++++++
spec/build/cpukit/librtemscpu.yml | 4 +
3 files changed, 452 insertions(+)
create mode 100644 cpukit/dev/flash/flashdev.c
create mode 100644 cpukit/include/dev/flash/flashdev.h
diff --git a/cpukit/dev/flash/flashdev.c b/cpukit/dev/flash/flashdev.c
new file mode 100644
index 0000000000..a37d0e6c3d
--- /dev/null
+++ b/cpukit/dev/flash/flashdev.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2023, 2023 Aaron Nyholm
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <dev/flash/flashdev.h>
+
+#include <rtems/imfs.h>
+#include <rtems/score/assert.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int flashdev_do_init(
+ flashdev *flash,
+ void (*destroy)(flashdev *flash)
+);
+
+void flashdev_destroy_and_free(flashdev *flash);
+
+void flashdev_destroy(flashdev *flash);
+
+static void flashdev_obtain(flashdev *flash) {
+ rtems_recursive_mutex_lock(&flash->mutex);
+}
+
+static void flashdev_release(flashdev *flash) {
+ rtems_recursive_mutex_unlock(&flash->mutex);
+}
+
+static ssize_t flashdev_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ size_t count
+ )
+{
+ flashdev *flash = IMFS_generic_get_context_by_iop(iop);
+
+ // Check reading from valid region
+ off_t new_offset = iop->offset + count;
+
+ if (iop->data1 != NULL && new_offset > ((flashdev_region*)iop->data1)->length) {
+ rtems_set_errno_and_return_minus_one(EINVAL);
+ }
+
+ // Read flash
+ off_t addr;
+ if (iop->data1 == NULL) {
+ addr = iop->offset;
+ } else {
+ addr = (iop->offset + ((flashdev_region*)iop->data1)->base);
+ }
+ flashdev_obtain(flash);
+ int status = (*flash->read)(flash->driver, addr, count, buffer);
+ flashdev_release(flash);
+
+ // Update offset and return
+ if (status == 0) {
+ iop->offset = new_offset;
+ return count;
+ } else {
+ rtems_set_errno_and_return_minus_one(-status);
+ }
+}
+
+static ssize_t flashdev_write(
+ rtems_libio_t *iop,
+ const void *buffer,
+ size_t count
+ )
+{
+ flashdev *flash = IMFS_generic_get_context_by_iop(iop);
+
+ // Check writing to valid region
+ off_t new_offset = iop->offset + count;
+
+ if (iop->data1 != NULL && new_offset > ((flashdev_region*)iop->data1)->length) {
+ rtems_set_errno_and_return_minus_one(EINVAL);
+ }
+
+ // Write to flash
+ off_t addr;
+ if (iop->data1 == NULL) {
+ addr = iop->offset;
+ } else {
+ addr = (iop->offset + ((flashdev_region*)iop->data1)->base);
+ }
+ flashdev_obtain(flash);
+ int status = (*flash->write)(flash->driver, addr, count, buffer);
+ flashdev_release(flash);
+
+ // Update offset and return
+ if (status == 0) {
+ iop->offset = new_offset;
+ return count;
+ } else {
+ rtems_set_errno_and_return_minus_one(-status);
+ }
+}
+
+static int flashdev_ioctl(
+ rtems_libio_t *iop,
+ ioctl_command_t command,
+ void *arg
+ )
+{
+ flashdev *flash = IMFS_generic_get_context_by_iop(iop);
+ int err = 0;
+
+ flashdev_obtain(flash);
+
+ switch (command) {
+ case FLASHDEV_IOCTL_OBTAIN:
+ flashdev_obtain(flash);
+ err = 0;
+ break;
+ case FLASHDEV_IOCTL_RELEASE:
+ flashdev_release(flash);
+ err = 0;
+ break;
+ case FLASHDEV_IOCTL_READID:
+ uint32_t *readID_out = arg;
+ *readID_out = (*flash->read_id)(flash);
+ err = 0;
+ break;
+ case FLASHDEV_IOCTL_ERASE:
+ erase_args *erase_args_1 = (erase_args*)arg;
+ // Check erasing valid region
+ off_t check_offset = erase_args_1->offset + erase_args_1->count;
+ if ((iop->data1 != NULL) &&
+ (check_offset > ((flashdev_region*)iop->data1)->length ||
+ (erase_args_1->offset < ((flashdev_region*)iop->data1)->base))
+ ) {
+ rtems_set_errno_and_return_minus_one(EINVAL);
+ }
+ // Erasing
+ off_t addr;
+ if (iop->data1 == NULL) {
+ addr = erase_args_1->offset;
+ } else {
+ addr = (erase_args_1->offset + ((flashdev_region*)iop->data1)->base);
+ }
+ (*flash->erase)(flash->driver, addr, erase_args_1->count);
+ err = 0;
+ break;
+ case FLASHDEV_IOCTL_REGION_SET:
+ err = 0;
+ flashdev_region *region_in = (flashdev_region*)arg;
+ if (region_in == NULL || region_in->base < 0 || region_in->length < 0) {
+ rtems_set_errno_and_return_minus_one(EINVAL);
+ }
+ flashdev_region *region_save = malloc(sizeof(flashdev_region));
+ if (region_save == NULL) {
+ rtems_set_errno_and_return_minus_one(ENOMEM);
+ }
+ iop->data1 = region_save;
+ ((flashdev_region*)iop->data1)->base = region_in->base;
+ ((flashdev_region*)iop->data1)->length = region_in->length;
+ iop->offset = region_in->base;
+ break;
+ case FLASHDEV_IOCTL_REGION_UNSET:
+ err = 0;
+ free((flashdev_region*)iop->data1);
+ iop->data1 = NULL;
+ break;
+ case FLASHDEV_IOCTL_TYPE:
+ int *type_out = arg;
+ *type_out = (*flash->flash_type)(flash);
+ err = 0;
+ break;
+ }
+
+ flashdev_release(flash);
+
+ if (err == 0) {
+ return 0;
+ } else {
+ rtems_set_errno_and_return_minus_one(err);
+ }
+}
+
+
+static off_t flashdev_lseek(
+ rtems_libio_t *iop,
+ off_t offset,
+ int whence
+)
+{
+ off_t tmp_offset;
+
+ if (offset < 0) {
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ switch (whence) {
+ case SEEK_CUR:
+ tmp_offset = iop->offset + offset;
+ break;
+ case SEEK_SET:
+ tmp_offset = offset;
+ break;
+ case SEEK_END:
+ default:
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ if (iop->data1 != NULL &&
+ (tmp_offset > ((flashdev_region*)iop->data1)->length)) {
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ iop->offset = tmp_offset;
+ return iop->offset;
+}
+
+static int flashdev_close(rtems_libio_t *iop) {
+ free((flashdev_region*)iop->data1);
+ return rtems_filesystem_default_close(iop);
+}
+
+static int flashdev_open(rtems_libio_t *iop, const char *path, int oflag, mode_t mode) {
+ int ret = rtems_filesystem_default_open(iop, path, oflag, mode);
+ iop->data1 = NULL;
+ return ret;
+}
+
+
+static const rtems_filesystem_file_handlers_r flashdev_handler = {
+ .open_h = flashdev_open,
+ .close_h = flashdev_close,
+ .read_h = flashdev_read,
+ .write_h = flashdev_write,
+ .ioctl_h = flashdev_ioctl,
+ .lseek_h = flashdev_lseek,
+ .fstat_h = IMFS_stat,
+ .ftruncate_h = rtems_filesystem_default_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .mmap_h = rtems_filesystem_default_mmap,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};
+
+static void flashdev_node_destroy(IMFS_jnode_t *node) {
+ flashdev *flash;
+
+ flash = IMFS_generic_get_context_by_node(node);
+
+ (*flash->destroy)(flash);
+
+ IMFS_node_destroy_default(node);
+
+}
+
+static const IMFS_node_control flashdev_node_control = IMFS_GENERIC_INITIALIZER(
+ &flashdev_handler,
+ IMFS_node_initialize_generic,
+ flashdev_node_destroy
+);
+
+int flashdev_register(
+ flashdev *flash,
+ const char *flash_path
+) {
+ int rv;
+
+ rv = IMFS_make_generic_node(
+ flash_path,
+ S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+ &flashdev_node_control,
+ flash
+ );
+ if (rv != 0) {
+ (*flash->destroy)(flash);
+ }
+
+ return rv;
+}
+
+int flashdev_do_init(
+ flashdev *flash,
+ void (*destroy)(flashdev *flash)
+) {
+ rtems_recursive_mutex_init(&flash->mutex, "FLASHDEV Flash");
+ flash->destroy = destroy;
+ return 0;
+}
+
+void flashdev_destroy(flashdev *flash) {
+ rtems_recursive_mutex_destroy(&flash->mutex);
+}
+
+void flashdev_destroy_and_free(flashdev *flash) {
+ rtems_recursive_mutex_destroy(&flash->mutex);
+ free(flash);
+}
+
+int flashdev_init(flashdev *flash) {
+ memset(flash, 0, sizeof(*flash));
+
+ return flashdev_do_init(flash, flashdev_destroy);
+}
+
+flashdev* flashdev_alloc_and_init(size_t size) {
+
+ flashdev *flash = NULL;
+
+ if (size >= sizeof(*flash)) {
+ flash = calloc(1, size);
+ if (flash != NULL) {
+ int rv;
+
+ rv = flashdev_do_init(flash, flashdev_destroy_and_free);
+ if (rv != 0) {
+ free(flash);
+ return NULL;
+ }
+ }
+ }
+
+ return flash;
+
+}
diff --git a/cpukit/include/dev/flash/flashdev.h b/cpukit/include/dev/flash/flashdev.h
new file mode 100644
index 0000000000..b6869629c4
--- /dev/null
+++ b/cpukit/include/dev/flash/flashdev.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup FLASHDEV_Flash
+ *
+ * @brief FLASHDEV flashdev API
+ */
+
+/*
+ * Copyright (C) 2023, 2023 Aaron Nyholm
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _DEV_FLASHDEV_H
+#define _DEV_FLASHDEV_H
+
+#include <rtems/thread.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+typedef struct flashdev flashdev;
+
+typedef struct erase_args {
+ uint32_t offset;
+ uint32_t count;
+} erase_args;
+
+typedef struct flashdev_region {
+ off_t base;
+ off_t length;
+} flashdev_region;
+
+struct flashdev {
+
+ int (*read)(void *driver, uint32_t offset, uint32_t count, void *buffer);
+
+ int (*write)(void *driver, uint32_t offset, uint32_t count, const void *buffer);
+
+ int (*erase)(void *driver, uint32_t offset, uint32_t count);
+
+ uint32_t (*read_id)(flashdev *flashdev);
+
+ int (*flash_type)(flashdev *flashdev);
+
+ void (*destroy)(flashdev *flashdev);
+
+ void *driver;
+
+ rtems_recursive_mutex mutex;
+
+};
+
+#define FLASHDEV_IOCTL_OBTAIN 0
+#define FLASHDEV_IOCTL_RELEASE 1
+#define FLASHDEV_IOCTL_READID 2
+#define FLASHDEV_IOCTL_ERASE 3
+#define FLASHDEV_IOCTL_REGION_SET 4
+#define FLASHDEV_IOCTL_REGION_UNSET 5
+#define FLASHDEV_IOCTL_TYPE 6
+
+#define FLASHDEV_TYPE_NOR 0
+#define FLASHDEV_TYPE_NAND 1
+
+flashdev* flashdev_alloc_and_init(size_t size);
+
+int flashdev_init(flashdev *flashdev);
+
+int flashdev_register(
+ flashdev *flashdev,
+ const char *flashdev_path
+);
+
+#endif /* _DEV_FLASHDEV_H */
diff --git a/spec/build/cpukit/librtemscpu.yml b/spec/build/cpukit/librtemscpu.yml
index 2c969aa5f6..86c5c8ff2b 100644
--- a/spec/build/cpukit/librtemscpu.yml
+++ b/spec/build/cpukit/librtemscpu.yml
@@ -52,6 +52,9 @@ install:
- destination: ${BSP_INCLUDEDIR}/dev/spi
source:
- cpukit/include/dev/spi/spi.h
+- destination: ${BSP_INCLUDEDIR}/dev/flash
+ source:
+ - cpukit/include/dev/flash/flashdev.h
- destination: ${BSP_INCLUDEDIR}/dev/can
source:
- cpukit/include/dev/can/can.h
@@ -522,6 +525,7 @@ links:
- role: build-dependency
uid: vckey
source:
+- cpukit/dev/flash/flashdev.c
- cpukit/dev/i2c/eeprom.c
- cpukit/dev/i2c/fpga-i2c-slave.c
- cpukit/dev/i2c/gpio-nxp-pca9535.c
--
2.25.1
More information about the devel
mailing list