<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><div dir="ltr"><div>I noticed that there is provision here to pass through the JEDEC ID from the physical device (obtained by a JEDEC parameter page read, ONFI parameter page read, or other mechanism).</div><div><br></div><div>Is this intended to be purely informational?<br></div><div><br></div><div>Kinsey<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Apr 20, 2023 at 2:23 AM <<a href="mailto:aaron.nyholm@unfoldedeffective.com">aaron.nyholm@unfoldedeffective.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">From: Aaron Nyholm <<a href="mailto:aaron.nyholm@southerninnovation.com" target="_blank">aaron.nyholm@southerninnovation.com</a>><br>
<br>
---<br>
 cpukit/dev/flash/flashdev.c         | 849 ++++++++++++++++++++++++++++<br>
 cpukit/include/dev/flash/flashdev.h | 458 +++++++++++++++<br>
 spec/build/cpukit/librtemscpu.yml   |   4 +<br>
 3 files changed, 1311 insertions(+)<br>
 create mode 100644 cpukit/dev/flash/flashdev.c<br>
 create mode 100644 cpukit/include/dev/flash/flashdev.h<br>
<br>
diff --git a/cpukit/dev/flash/flashdev.c b/cpukit/dev/flash/flashdev.c<br>
new file mode 100644<br>
index 0000000000..03343f015f<br>
--- /dev/null<br>
+++ b/cpukit/dev/flash/flashdev.c<br>
@@ -0,0 +1,849 @@<br>
+/*<br>
+ * Copyright (C) 2023 Aaron Nyholm<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+<br>
+#ifdef HAVE_CONFIG_H<br>
+#include "config.h"<br>
+#endif<br>
+<br>
+#include <dev/flash/flashdev.h><br>
+<br>
+#include <rtems/imfs.h><br>
+#include <rtems/score/assert.h><br>
+<br>
+#include <errno.h><br>
+#include <fcntl.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <unistd.h><br>
+<br>
+#define RTEMS_FLASHDEV_REGION_ALLOC_FULL 0xFFFFFFFFUL<br>
+#define RTEMS_FLASHDEV_REGION_UNDEFINED 0xFFFFFFFFUL<br>
+#define RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH 32<br>
+<br>
+static int rtems_flashdev_do_init(<br>
+  rtems_flashdev *flash,<br>
+  void ( *destroy )( rtems_flashdev *flash )<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_erase(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  void *arg<br>
+);<br>
+<br>
+static off_t rtems_flashdev_get_region_offset(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop<br>
+);<br>
+<br>
+static size_t rtems_flashdev_get_region_size(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_set_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  void *arg<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_create_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  rtems_flashdev_region *region_in<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_update_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  rtems_flashdev_region *region_in<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_clear_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_ioctl_jedec_id(<br>
+  rtems_flashdev *flash<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_ioctl_flash_type(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_pageinfo_offset(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_pageinfo_index(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_page_count(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+);<br>
+<br>
+static int rtems_flashdev_ioctl_write_block_size(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+);<br>
+<br>
+static int rtems_flashdev_get_addr(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  size_t count,<br>
+  off_t *addr<br>
+);<br>
+<br>
+static int rtems_flashdev_update_and_return(<br>
+  rtems_libio_t *iop,<br>
+  int status,<br>
+  size_t count,<br>
+  off_t new_offset<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_find_unalloced_region(<br>
+  rtems_flashdev_region_table *region_table<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_set_region(<br>
+  rtems_flashdev_region_table *region_table,<br>
+  int index<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_unset_region(<br>
+  rtems_flashdev_region_table *region_table,<br>
+  int index<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_check_allocation(<br>
+  rtems_flashdev_region_table *region_table,<br>
+  int index<br>
+);<br>
+<br>
+static uint32_t rtems_flashdev_get_region_index(<br>
+  rtems_libio_t *iop<br>
+)<br>
+{<br>
+  return (uint32_t)iop->data0;<br>
+}<br>
+<br>
+static int rtems_flashdev_is_region_defined(<br>
+  rtems_libio_t *iop<br>
+)<br>
+{<br>
+  return (rtems_flashdev_get_region_index( iop ) != RTEMS_FLASHDEV_REGION_UNDEFINED);<br>
+}<br>
+<br>
+static void rtems_flashdev_set_region_index(<br>
+  rtems_libio_t *iop,<br>
+  uint32_t index<br>
+)<br>
+{<br>
+  iop->data0 = index;<br>
+}<br>
+<br>
+static int rtems_flashdev_check_offset_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  off_t offset<br>
+)<br>
+{<br>
+  if ( ( rtems_flashdev_is_region_defined( iop ) ) &&<br>
+       ( offset > rtems_flashdev_get_region_size( flash, iop ) ) ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+  return 0;<br>
+}<br>
+<br>
+static void rtems_flashdev_obtain( rtems_flashdev *flash )<br>
+{<br>
+  rtems_recursive_mutex_lock( &flash->mutex );<br>
+}<br>
+<br>
+static void rtems_flashdev_release( rtems_flashdev *flash )<br>
+{<br>
+  rtems_recursive_mutex_unlock( &flash->mutex );<br>
+}<br>
+<br>
+static ssize_t rtems_flashdev_read(<br>
+  rtems_libio_t *iop,<br>
+  void *buffer,<br>
+  size_t count<br>
+)<br>
+{<br>
+  rtems_flashdev *flash = IMFS_generic_get_context_by_iop( iop );<br>
+  off_t addr;<br>
+  int status;<br>
+<br>
+  if ( flash->read == NULL ) {<br>
+    return 0;<br>
+  }<br>
+<br>
+  /* Get flash address */<br>
+  status = rtems_flashdev_get_addr( flash, iop, count, &addr );<br>
+  if ( status == -1 ) {<br>
+    return status;<br>
+  }<br>
+<br>
+  /* Read flash */<br>
+  rtems_flashdev_obtain( flash );<br>
+  status = ( *flash->read )( flash, addr, count, buffer );<br>
+  rtems_flashdev_release( flash );<br>
+<br>
+  /* Update offset and return */<br>
+  return rtems_flashdev_update_and_return( iop, status, count, addr + count );<br>
+}<br>
+<br>
+static ssize_t rtems_flashdev_write(<br>
+  rtems_libio_t *iop,<br>
+  const void *buffer,<br>
+  size_t count<br>
+)<br>
+{<br>
+  rtems_flashdev *flash = IMFS_generic_get_context_by_iop( iop );<br>
+  off_t addr;<br>
+  int status;<br>
+<br>
+  if ( flash->write == NULL ) {<br>
+    return 0;<br>
+  }<br>
+<br>
+  /* Get flash address */<br>
+  status = rtems_flashdev_get_addr( flash, iop, count, &addr );<br>
+  if ( status == -1 ) {<br>
+    return status;<br>
+  }<br>
+<br>
+  /* Write to flash */<br>
+  rtems_flashdev_obtain( flash );<br>
+  status = ( *flash->write )( flash, addr, count, buffer );<br>
+  rtems_flashdev_release( flash );<br>
+<br>
+  /* Update offset and return */<br>
+  return rtems_flashdev_update_and_return( iop, status, count, addr + count );<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl(<br>
+  rtems_libio_t *iop,<br>
+  ioctl_command_t command,<br>
+  void *arg<br>
+)<br>
+{<br>
+  rtems_flashdev *flash = IMFS_generic_get_context_by_iop( iop );<br>
+  int err = 0;<br>
+<br>
+  rtems_flashdev_obtain( flash );<br>
+<br>
+  switch ( command ) {<br>
+    case RTEMS_FLASHDEV_IOCTL_OBTAIN:<br>
+      rtems_flashdev_obtain( flash );<br>
+      err = 0;<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_RELEASE:<br>
+      rtems_flashdev_release( flash );<br>
+      err = 0;<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_JEDEC_ID:<br>
+      *( (uint32_t *) arg ) = rtems_flashdev_ioctl_jedec_id( flash );<br>
+      err = 0;<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_ERASE:<br>
+      err = rtems_flashdev_ioctl_erase( flash, iop, arg );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_REGION_SET:<br>
+      err = rtems_flashdev_ioctl_set_region( flash, iop, arg );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_REGION_UNSET:<br>
+      err = rtems_flashdev_ioctl_clear_region( flash, iop );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_TYPE:<br>
+      err = rtems_flashdev_ioctl_flash_type( flash, arg );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_OFFSET:<br>
+      err = rtems_flashdev_ioctl_pageinfo_offset( flash, arg );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_INDEX:<br>
+      err = rtems_flashdev_ioctl_pageinfo_index( flash, arg );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_PAGE_COUNT:<br>
+      err = rtems_flashdev_ioctl_page_count( flash, arg );<br>
+      break;<br>
+    case RTEMS_FLASHDEV_IOCTL_WRITE_BLOCK_SIZE:<br>
+      err = rtems_flashdev_ioctl_write_block_size( flash, arg );<br>
+      break;<br>
+  }<br>
+<br>
+  rtems_flashdev_release( flash );<br>
+  if ( err != 0 ) {<br>
+    rtems_set_errno_and_return_minus_one( err );<br>
+  } else {<br>
+    return 0;<br>
+  }<br>
+}<br>
+<br>
+static off_t rtems_flashdev_lseek(<br>
+  rtems_libio_t *iop,<br>
+  off_t offset,<br>
+  int whence<br>
+)<br>
+{<br>
+  off_t tmp_offset;<br>
+  rtems_flashdev *flash = IMFS_generic_get_context_by_iop( iop );<br>
+<br>
+  if ( offset < 0 ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+<br>
+  switch ( whence ) {<br>
+    case SEEK_CUR:<br>
+      tmp_offset = iop->offset + offset;<br>
+      break;<br>
+    case SEEK_SET:<br>
+      tmp_offset = offset;<br>
+      break;<br>
+    case SEEK_END:<br>
+    default:<br>
+      rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+<br>
+  if ( ( rtems_flashdev_is_region_defined(iop) ) &&<br>
+       ( tmp_offset > rtems_flashdev_get_region_size( flash, iop ) ) ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+<br>
+  iop->offset = tmp_offset;<br>
+  return iop->offset;<br>
+}<br>
+<br>
+static int rtems_flashdev_close( rtems_libio_t *iop )<br>
+{<br>
+  rtems_flashdev *flash = IMFS_generic_get_context_by_iop( iop );<br>
+  rtems_flashdev_ioctl_clear_region( flash, iop );<br>
+  return rtems_filesystem_default_close( iop );<br>
+}<br>
+<br>
+static int rtems_flashdev_open(<br>
+  rtems_libio_t *iop,<br>
+  const char *path,<br>
+  int oflag,<br>
+  mode_t mode<br>
+)<br>
+{<br>
+  int ret = rtems_filesystem_default_open( iop, path, oflag, mode );<br>
+  rtems_flashdev_set_region_index(iop, RTEMS_FLASHDEV_REGION_UNDEFINED);<br>
+  return ret;<br>
+}<br>
+<br>
+static const rtems_filesystem_file_handlers_r rtems_flashdev_handler = {<br>
+  .open_h = rtems_flashdev_open,<br>
+  .close_h = rtems_flashdev_close,<br>
+  .read_h = rtems_flashdev_read,<br>
+  .write_h = rtems_flashdev_write,<br>
+  .ioctl_h = rtems_flashdev_ioctl,<br>
+  .lseek_h = rtems_flashdev_lseek,<br>
+  .fstat_h = IMFS_stat,<br>
+  .ftruncate_h = rtems_filesystem_default_ftruncate,<br>
+  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,<br>
+  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,<br>
+  .fcntl_h = rtems_filesystem_default_fcntl,<br>
+  .kqfilter_h = rtems_filesystem_default_kqfilter,<br>
+  .mmap_h = rtems_filesystem_default_mmap,<br>
+  .poll_h = rtems_filesystem_default_poll,<br>
+  .readv_h = rtems_filesystem_default_readv,<br>
+  .writev_h = rtems_filesystem_default_writev };<br>
+<br>
+static void rtems_flashdev_node_destroy( IMFS_jnode_t *node )<br>
+{<br>
+  rtems_flashdev *flash;<br>
+<br>
+  flash = IMFS_generic_get_context_by_node( node );<br>
+<br>
+  ( *flash->destroy )( flash );<br>
+<br>
+  IMFS_node_destroy_default( node );<br>
+}<br>
+<br>
+static const IMFS_node_control<br>
+  rtems_flashdev_node_control = IMFS_GENERIC_INITIALIZER(<br>
+    &rtems_flashdev_handler,<br>
+    IMFS_node_initialize_generic,<br>
+    rtems_flashdev_node_destroy<br>
+);<br>
+<br>
+int rtems_flashdev_register( rtems_flashdev *flash, const char *flash_path )<br>
+{<br>
+  int rv;<br>
+  rtems_flashdev_region_table *table = flash->region_table;<br>
+  int alloc_array_len;<br>
+<br>
+  rv = IMFS_make_generic_node( flash_path,<br>
+                               S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,<br>
+                               &rtems_flashdev_node_control,<br>
+                               flash );<br>
+  if ( rv != 0 ) {<br>
+    ( *flash->destroy )( flash );<br>
+  }<br>
+<br>
+<br>
+  if (table != NULL) {<br>
+    alloc_array_len = table->max_regions/RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH +<br>
+      ((table->max_regions%RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH) != 0);<br>
+    for<br>
+    (<br>
+      int i = 0;<br>
+      i < alloc_array_len;<br>
+      i++<br>
+    )<br>
+    {<br>
+      table->bit_allocator[i] = 0;<br>
+    }<br>
+  }<br>
+<br>
+  return rv;<br>
+}<br>
+<br>
+static int rtems_flashdev_do_init(<br>
+  rtems_flashdev *flash,<br>
+  void ( *destroy )( rtems_flashdev *flash )<br>
+)<br>
+{<br>
+  rtems_recursive_mutex_init( &flash->mutex, "RTEMS_FLASHDEV Flash" );<br>
+  flash->destroy = destroy;<br>
+  flash->read = NULL;<br>
+  flash->write = NULL;<br>
+  flash->erase = NULL;<br>
+  flash->jedec_id = NULL;<br>
+  flash->flash_type = NULL;<br>
+  flash->page_info_by_offset = NULL;<br>
+  flash->page_info_by_index = NULL;<br>
+  flash->page_count = NULL;<br>
+  flash->write_block_size = NULL;<br>
+  flash->region_table = NULL;<br>
+  return 0;<br>
+}<br>
+<br>
+void rtems_flashdev_destroy( rtems_flashdev *flash )<br>
+{<br>
+  rtems_recursive_mutex_destroy( &flash->mutex );<br>
+}<br>
+<br>
+void rtems_flashdev_destroy_and_free( rtems_flashdev *flash )<br>
+{<br>
+  if ( flash == NULL ) {<br>
+    return;<br>
+  }<br>
+  rtems_recursive_mutex_destroy( &( flash->mutex ) );<br>
+  free( flash );<br>
+  flash = NULL;<br>
+  return;<br>
+}<br>
+<br>
+int rtems_flashdev_init( rtems_flashdev *flash )<br>
+{<br>
+  memset( flash, 0, sizeof( *flash ) );<br>
+<br>
+  return rtems_flashdev_do_init( flash, rtems_flashdev_destroy );<br>
+}<br>
+<br>
+rtems_flashdev *rtems_flashdev_alloc_and_init( size_t size )<br>
+{<br>
+  rtems_flashdev *flash = NULL;<br>
+<br>
+  if ( size >= sizeof( *flash ) ) {<br>
+    flash = calloc( 1, size );<br>
+    if ( flash != NULL ) {<br>
+      int rv;<br>
+<br>
+      rv = rtems_flashdev_do_init( flash, rtems_flashdev_destroy_and_free );<br>
+      if ( rv != 0 ) {<br>
+        rtems_recursive_mutex_destroy( &flash->mutex );<br>
+        free( flash );<br>
+        return NULL;<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+  return flash;<br>
+}<br>
+<br>
+static int rtems_flashdev_get_addr(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  size_t count,<br>
+  off_t *addr<br>
+)<br>
+{<br>
+  off_t new_offset;<br>
+<br>
+  /* Check address is in valid region */<br>
+  new_offset = iop->offset + count;<br>
+<br>
+  if (rtems_flashdev_check_offset_region(flash, iop, new_offset)) {<br>
+    return -1;<br>
+  }<br>
+<br>
+  /* Get address for operation */<br>
+  if ( !rtems_flashdev_is_region_defined( iop ) ) {<br>
+    *addr = iop->offset;<br>
+  } else {<br>
+    *addr = ( iop->offset + rtems_flashdev_get_region_offset( flash, iop ) );<br>
+  }<br>
+  return 0;<br>
+}<br>
+<br>
+static int rtems_flashdev_update_and_return(<br>
+  rtems_libio_t *iop,<br>
+  int status,<br>
+  size_t count,<br>
+  off_t new_offset<br>
+)<br>
+{<br>
+  /* Update offset and return */<br>
+  if ( status == 0 ) {<br>
+    iop->offset = new_offset;<br>
+    return count;<br>
+  } else {<br>
+    rtems_set_errno_and_return_minus_one( status );<br>
+  }<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_erase(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  void *arg<br>
+)<br>
+{<br>
+  rtems_flashdev_region *erase_args_1;<br>
+  off_t check_offset;<br>
+  int status;<br>
+<br>
+  if ( flash->erase == NULL ) {<br>
+    return 0;<br>
+  }<br>
+<br>
+  erase_args_1 = (rtems_flashdev_region *) arg;<br>
+  /* Check erasing valid region */<br>
+  check_offset = erase_args_1->offset + erase_args_1->size;<br>
+  if ( rtems_flashdev_is_region_defined( iop ) && (<br>
+         rtems_flashdev_check_offset_region(flash, iop, check_offset) ||<br>
+         ( erase_args_1->offset <<br>
+           rtems_flashdev_get_region_offset( flash, iop ) ) ) ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+<br>
+  /* Erase flash */<br>
+  status = ( *flash->erase )( flash, erase_args_1->offset, erase_args_1->size );<br>
+  return status;<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_set_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  void *arg<br>
+)<br>
+{<br>
+  rtems_flashdev_region *region_in;<br>
+  rtems_flashdev_region_table *table = flash->region_table;<br>
+  region_in = (rtems_flashdev_region *) arg;<br>
+<br>
+  if (flash->region_table == NULL) {<br>
+    rtems_set_errno_and_return_minus_one( ENOMEM );<br>
+  }<br>
+<br>
+  if ( !rtems_flashdev_is_region_defined( iop ) &&<br>
+       rtems_flashdev_find_unalloced_region(table)<br>
+          == RTEMS_FLASHDEV_REGION_ALLOC_FULL)<br>
+  {<br>
+    /* New region to allocate and all regions allocated */<br>
+    rtems_set_errno_and_return_minus_one( ENOMEM );<br>
+  } else if ( !rtems_flashdev_is_region_defined( iop ) &&<br>
+              rtems_flashdev_find_unalloced_region(table) !=<br>
+                RTEMS_FLASHDEV_REGION_ALLOC_FULL ) {<br>
+    /* New region to allocate and space to allocate region */<br>
+    return rtems_flashdev_ioctl_create_region( flash, iop, region_in );<br>
+  } else {<br>
+    /* Updating existing region */<br>
+    return rtems_flashdev_ioctl_update_region( flash, iop, region_in );<br>
+  }<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_create_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  rtems_flashdev_region *region_in<br>
+)<br>
+{<br>
+  int i;<br>
+  rtems_flashdev_region_table *table = flash->region_table;<br>
+<br>
+  /* Find unallocated region slot */<br>
+  i = rtems_flashdev_find_unalloced_region(flash->region_table);<br>
+<br>
+  /* Set region values */<br>
+  table->regions[ i ].offset = region_in->offset;<br>
+  table->regions[ i ].size = region_in->size;<br>
+<br>
+  /* Set region as allocated and link iop */<br>
+  rtems_flashdev_set_region(flash->region_table, i);<br>
+  rtems_flashdev_set_region_index( iop, i );<br>
+  <br>
+  return 0;<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_update_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop,<br>
+  rtems_flashdev_region *region_in<br>
+)<br>
+{<br>
+  uint32_t region_index = rtems_flashdev_get_region_index( iop );<br>
+  rtems_flashdev_region_table *table = flash->region_table;<br>
+<br>
+  /**<br>
+   * If region index is larger then maximum region index or region<br>
+   * index at given index is undefined return an error.<br>
+   */<br>
+  if ( <br>
+       ( region_index >= flash->region_table->max_regions ) ||<br>
+       ( rtems_flashdev_check_allocation( table, region_index ) == 0)<br>
+     )<br>
+  {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+<br>
+  /* Set region values */<br>
+  table->regions[ region_index ].offset = region_in->offset;<br>
+  table->regions[ region_index ].size = region_in->size;<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_clear_region(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop<br>
+)<br>
+{<br>
+  uint32_t region_index = rtems_flashdev_get_region_index( iop );<br>
+<br>
+  if (flash->region_table == NULL) {<br>
+    rtems_set_errno_and_return_minus_one( ENOMEM );<br>
+  }<br>
+<br>
+  /* Check region to clear */<br>
+  if ( region_index == RTEMS_FLASHDEV_REGION_UNDEFINED ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+<br>
+  /* Clear region */<br>
+  rtems_flashdev_unset_region( flash->region_table, region_index );<br>
+  rtems_flashdev_set_region_index( iop, RTEMS_FLASHDEV_REGION_UNDEFINED );<br>
+  return 0;<br>
+}<br>
+<br>
+static off_t rtems_flashdev_get_region_offset(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop<br>
+)<br>
+{<br>
+  rtems_flashdev_region_table *table = flash->region_table;<br>
+  return table->regions[ rtems_flashdev_get_region_index( iop ) ].offset;<br>
+}<br>
+<br>
+static size_t rtems_flashdev_get_region_size(<br>
+  rtems_flashdev *flash,<br>
+  rtems_libio_t *iop<br>
+)<br>
+{<br>
+  rtems_flashdev_region_table *table = flash->region_table;<br>
+  return table->regions[ rtems_flashdev_get_region_index( iop ) ].size;<br>
+}<br>
+<br>
+static uint32_t rtems_flashdev_ioctl_jedec_id( rtems_flashdev *flash )<br>
+{<br>
+  if ( flash->jedec_id == NULL ) {<br>
+    return 0;<br>
+  } else {<br>
+    return ( *flash->jedec_id )( flash );<br>
+  }<br>
+}<br>
+<br>
+static uint32_t rtems_flashdev_ioctl_flash_type(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+)<br>
+{<br>
+  rtems_flashdev_flash_type *type = (rtems_flashdev_flash_type*)arg;<br>
+  if ( flash->flash_type == NULL ) {<br>
+    return 0;<br>
+  } else {<br>
+    return ( *flash->flash_type )( flash, type );<br>
+  }<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_pageinfo_offset(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+)<br>
+{<br>
+  rtems_flashdev_ioctl_page_info *page_info;<br>
+<br>
+  if ( arg == NULL ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+  if ( flash->page_info_by_offset == NULL ) {<br>
+    return 0;<br>
+  } else {<br>
+    page_info = (rtems_flashdev_ioctl_page_info *) arg;<br>
+    return ( *flash->page_info_by_offset )( flash,<br>
+                                         page_info->location,<br>
+                                         &page_info->page_info.offset,<br>
+                                         &page_info->page_info.size );<br>
+  }<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_pageinfo_index( rtems_flashdev *flash,<br>
+                                                void *arg )<br>
+{<br>
+  rtems_flashdev_ioctl_page_info *page_info;<br>
+<br>
+  if ( arg == NULL ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+  if ( flash->page_info_by_index == NULL ) {<br>
+    return 0;<br>
+  } else {<br>
+    page_info = (rtems_flashdev_ioctl_page_info *) arg;<br>
+    return ( *flash->page_info_by_index )( flash,<br>
+                                           page_info->location,<br>
+                                           &page_info->page_info.offset,<br>
+                                           &page_info->page_info.size );<br>
+  }<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_page_count( rtems_flashdev *flash, void *arg )<br>
+{<br>
+  if ( arg == NULL ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+  if ( flash->page_count == NULL ) {<br>
+    return 0;<br>
+  } else {<br>
+    return ( *flash->page_count )( flash, ( (int *) arg ) );<br>
+  }<br>
+}<br>
+<br>
+static int rtems_flashdev_ioctl_write_block_size(<br>
+  rtems_flashdev *flash,<br>
+  void *arg<br>
+)<br>
+{<br>
+  if ( arg == NULL ) {<br>
+    rtems_set_errno_and_return_minus_one( EINVAL );<br>
+  }<br>
+  if ( flash->write_block_size == NULL ) {<br>
+    return 0;<br>
+  } else {<br>
+    return ( *flash->write_block_size )( flash, ( (size_t *) arg ) );<br>
+  }<br>
+}<br>
+<br>
+static uint32_t rtems_flashdev_find_unalloced_region(<br>
+  rtems_flashdev_region_table *region_table<br>
+)<br>
+{<br>
+  int final_index =<br>
+    ( region_table->max_regions / RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH );<br>
+<br>
+  for ( int i = 0; i < final_index; i++ ) {<br>
+    /* If region the next 32 regions are full check the next allocator */<br>
+    if (region_table->bit_allocator[ i ] == RTEMS_FLASHDEV_REGION_ALLOC_FULL) {<br>
+      continue;<br>
+    }<br>
+<br>
+    for (int x = 0; x < RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH; x++) {<br>
+      if ( ! ( ( ( region_table->bit_allocator[ i ] ) >> x ) & 1UL ) ) {<br>
+        return RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH * i + x;<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+  for<br>
+  (<br>
+    int i = 0;<br>
+    i < ( region_table->max_regions % RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH );<br>
+    i++<br>
+  )<br>
+  {<br>
+    if ( ! ( ( ( region_table->bit_allocator[ final_index ] ) >> i ) & 1UL ) ) {<br>
+      return RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH * final_index + i;<br>
+    }<br>
+  }<br>
+<br>
+  return RTEMS_FLASHDEV_REGION_ALLOC_FULL;<br>
+<br>
+}<br>
+<br>
+static uint32_t rtems_flashdev_set_region(<br>
+  rtems_flashdev_region_table *region_table,<br>
+  int index<br>
+)<br>
+{<br>
+  int array_index = index / RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH;<br>
+  int shift = index % RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH;<br>
+<br>
+  region_table->bit_allocator[ array_index ] |= 1UL << shift;<br>
+<br>
+  return index;<br>
+}<br>
+<br>
+static uint32_t rtems_flashdev_unset_region(<br>
+  rtems_flashdev_region_table *region_table,<br>
+  int index<br>
+)<br>
+{<br>
+  int array_index = index / RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH;<br>
+  int shift = index % RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH;<br>
+<br>
+  region_table->bit_allocator[ array_index ] &= ~( 1UL << shift );<br>
+<br>
+  return index;<br>
+}<br>
+<br>
+static uint32_t rtems_flashdev_check_allocation(<br>
+  rtems_flashdev_region_table *region_table,<br>
+  int index<br>
+)<br>
+{<br>
+  int array_index = index / RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH;<br>
+  int shift = index%RTEMS_FLASHDEV_REGION_BITALLOC_LENGTH;<br>
+<br>
+  return ( ( region_table->bit_allocator[ array_index ] >> shift ) & 1UL );<br>
+}<br>
diff --git a/cpukit/include/dev/flash/flashdev.h b/cpukit/include/dev/flash/flashdev.h<br>
new file mode 100644<br>
index 0000000000..aee585d252<br>
--- /dev/null<br>
+++ b/cpukit/include/dev/flash/flashdev.h<br>
@@ -0,0 +1,458 @@<br>
+/* SPDX-License-Identifier: BSD-2-Clause */<br>
+<br>
+/**<br>
+ * @file<br>
+ *<br>
+ * @ingroup Flash<br>
+ *<br>
+ * @brief Generic Flash API<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (C) 2023 Aaron Nyholm<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+<br>
+#ifndef _DEV_FLASHDEV_H<br>
+#define _DEV_FLASHDEV_H<br>
+<br>
+#include <rtems/thread.h><br>
+#include <sys/types.h><br>
+<br>
+typedef struct rtems_flashdev rtems_flashdev;<br>
+<br>
+/**<br>
+ * @defgroup Generic Flash API<br>
+ *<br>
+ * @ingroup RTEMSDeviceDrivers<br>
+ *<br>
+ * @brief Generic Flash API to wrap specific device drivers.<br>
+ *<br>
+ * @{<br>
+ */<br>
+<br>
+/* IOCTL Calls */<br>
+<br>
+/**<br>
+ * @brief Obtains the flash device.<br>
+ *<br>
+ * This command has no argument.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_OBTAIN 0<br>
+/**<br>
+ * @brief Releases the flash device.<br>
+ *<br>
+ * This command has no argument.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_RELEASE 1<br>
+/**<br>
+ * @brief Returns the JEDEC ID of the flash device.<br>
+ *<br>
+ * @param[out] jedec_id Pointer to uint32_t in which the JEDEC ID is<br>
+ * returned in.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_JEDEC_ID 2<br>
+/**<br>
+ * @brief Erases flash device.<br>
+ *<br>
+ * @param[in] erase_args Pointer to rtems_flashdev_region struct<br>
+ * containing offset and size of erase to be performed.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_ERASE 3<br>
+/**<br>
+ * @brief Set a region that limits read, write and erase calls to within it.<br>
+ * Regions are file descriptor specific and limited to a single region per<br>
+ * file descriptor and 32 regions total per flash device. Regions can be<br>
+ * changed or updated by calling this IOCTL again.<br>
+ *<br>
+ * @param[in] region Pointer to rtems_flashdev_region struct containing<br>
+ * base and length of defined region.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_REGION_SET 4<br>
+/**<br>
+ * @brief Removes the set region on the file descriptor.<br>
+ *<br>
+ * This command has no argument.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_REGION_UNSET 5<br>
+/**<br>
+ * @brief Returns the type of flash device (e.g. NOR or NAND).<br>
+ *<br>
+ * @param[out] flash_type Pointer to integer which is set to the flash<br>
+ * type macro value.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_TYPE 6<br>
+<br>
+/**<br>
+ * @brief Get the size and address of flash page at given offset<br>
+ *<br>
+ * The offset ignores the region limiting. To find page of region<br>
+ * limited offset add the base of the region to the desired offset.<br>
+ *<br>
+ * @param[in,out] rtems_flashdev_ioctl_page_info arg Pointer to struct<br>
+ * with offset and space for return values.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_OFFSET 7<br>
+<br>
+/**<br>
+ * @brief Get the size and address of nth flash page where n is index passed in.<br>
+ *<br>
+ * The index ignores the region limiting.<br>
+ *<br>
+ * @param[in,out] rtems_flashdev_ioctl_page_info arg Pointer to struct<br>
+ * with index and space for return values.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_INDEX 8<br>
+<br>
+/**<br>
+ * @brief Get the number of pages in flash device.<br>
+ *<br>
+ * @param[out] count Integer containing the number of pages.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_PAGE_COUNT 9<br>
+<br>
+/**<br>
+ * @brief Get the minimum write size supported by the driver.<br>
+ *<br>
+ * @param[out] count Integer containing the minimum write size.<br>
+ */<br>
+#define RTEMS_FLASHDEV_IOCTL_WRITE_BLOCK_SIZE 10<br>
+<br>
+/**<br>
+ * @brief The maximum number of region limited file descriptors<br>
+ * allowed to be open at once.<br>
+ */<br>
+#define RTEMS_FLASHDEV_MAX_REGIONS 32<br>
+<br>
+/**<br>
+ * @brief Enum for flash type returned from IOCTL call.<br>
+ */<br>
+typedef enum rtems_flashdev_flash_type {<br>
+  /**<br>
+   * @brief The flash device is NOR flash.<br>
+   **/<br>
+  RTEMS_FLASHDEV_NOR,<br>
+  /**<br>
+   * @brief The flash device is NAND flash.<br>
+   */<br>
+  RTEMS_FLASHDEV_NAND<br>
+} rtems_flashdev_flash_type;<br>
+<br>
+/**<br>
+ * @brief General definition for on flash device.<br>
+ */<br>
+typedef struct rtems_flashdev_region {<br>
+  /**<br>
+   * @brief Base of region.<br>
+   */<br>
+  off_t offset;<br>
+  /**<br>
+   * @brief Length of region.<br>
+   */<br>
+  size_t size;<br>
+} rtems_flashdev_region;<br>
+<br>
+/**<br>
+ * @brief Struct holding region definitions<br>
+ */<br>
+typedef struct rtems_flashdev_region_table {<br>
+  /**<br>
+   * @brief The maximum regions that can be defined at once.<br>
+   */<br>
+  int max_regions;<br>
+<br>
+  /**<br>
+   * @brief Pointer to array of rtems_flashdev_region of length<br>
+   * max_regions<br>
+   */<br>
+  rtems_flashdev_region* regions;<br>
+<br>
+  /**<br>
+   * @brief Array of uint32_t acting as bit allocator<br>
+   * for regions array.<br>
+   */<br>
+  uint32_t *bit_allocator;<br>
+} rtems_flashdev_region_table;<br>
+<br>
+/**<br>
+ * @brief Page information returned from IOCTL calls.<br>
+ */<br>
+typedef struct rtems_flashdev_ioctl_page_info {<br>
+  /**<br>
+   * @brief Offset or index to find page at.<br>
+   */<br>
+  off_t location;<br>
+<br>
+  /**<br>
+   * @brief Information returned about the page. Including the <br>
+   * base offset and size of page.<br>
+   */<br>
+  rtems_flashdev_region page_info;<br>
+} rtems_flashdev_ioctl_page_info;<br>
+<br>
+/**<br>
+ * @brief Flash device.<br>
+ */<br>
+struct rtems_flashdev {<br>
+  /**<br>
+   * @brief Call to the device driver to read the flash device.<br>
+   *<br>
+   * @param[in] flash Pointer to flash device.<br>
+   * @param[in] offset Address to read from.<br>
+   * @param[in] count Number of bytes to read.<br>
+   * @param[out] buffer Buffer for data to be read into.<br>
+   *<br>
+   * @retval 0 Successful operation.<br>
+   * @retval 1 Failed operation.<br>
+   */<br>
+  int ( *read )(<br>
+    rtems_flashdev *flash,<br>
+    uintptr_t offset,<br>
+    size_t count,<br>
+    void *buffer<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to the device driver to write to the flash device.<br>
+   *<br>
+   * @param[in] flash Pointer to flash device.<br>
+   * @param[in] offset Address to write to.<br>
+   * @param[in] count Number of bytes to read.<br>
+   * @param[in] buffer Buffer for data to be written from.<br>
+   *<br>
+   * @retval 0 Successful operation.<br>
+   * @retval 1 Failed operation.<br>
+   */<br>
+  int ( *write )(<br>
+    rtems_flashdev *flash,<br>
+    uintptr_t offset,<br>
+    size_t count,<br>
+    const void *buffer<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to the device driver to erase the flash device.<br>
+   *<br>
+   * @param[in] flash Pointer to flash device.<br>
+   * @param[in] offset Address to erase at.<br>
+   * @param[in] count Number of bytes to erase.<br>
+   *<br>
+   * @retval 0 Successful operation.<br>
+   * @retval 1 Failed operation.<br>
+   */<br>
+  int ( *erase )(<br>
+    rtems_flashdev *flash,<br>
+    uintptr_t offset,<br>
+    size_t count<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to the device driver to return the JEDEC ID.<br>
+   *<br>
+   * @param[in] flash The flash device.<br>
+   *<br>
+   * @retval JEDEC ID.<br>
+   */<br>
+  uint32_t ( *jedec_id )(<br>
+    rtems_flashdev *flash<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to the device driver to return the flash type.<br>
+   *<br>
+   * @param[in] flash The flash device.<br>
+   * @param[out] type The type of flash device.<br>
+   *<br>
+   * @retval 0 Success<br>
+   * @retbal Other Failure<br>
+   */<br>
+  int ( *flash_type )(<br>
+    rtems_flashdev *flash,<br>
+    rtems_flashdev_flash_type *type<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to device driver to get size and offset of page at<br>
+   * given offset.<br>
+   *<br>
+   * @param[in] flash The flash device<br>
+   * @param[in] search_offset The offset of the page which info is to be<br>
+   * returned.<br>
+   * @param[out] page_offset The offset of the start of the page<br>
+   * @param[out] page_size The size of the page<br>
+   *<br>
+   * @retval 0 Success.<br>
+   * @retval non-zero Failed.<br>
+   */<br>
+  int ( *page_info_by_offset )(<br>
+    rtems_flashdev *flash,<br>
+    off_t search_offset,<br>
+    off_t *page_offset,<br>
+    size_t *page_size<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to device driver to get size and offset of page at<br>
+   * given index.<br>
+   *<br>
+   * @param[in] flash The flash device<br>
+   * @param[in] search_index The index of the page which info is to be returned.<br>
+   * @param[out] page_offset The offset of the start of the page<br>
+   * @param[out] page_size The size of the page<br>
+   *<br>
+   * @retval 0 Success.<br>
+   * @retval non-zero Failed.<br>
+   */<br>
+  int ( *page_info_by_index )(<br>
+    rtems_flashdev *flashdev,<br>
+    off_t search_index,<br>
+    off_t *page_offset,<br>
+    size_t *page_size<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to device driver to return the number of pages on the flash<br>
+   * device.<br>
+   *<br>
+   * @param[out] page_count The number of pages on the flash device.<br>
+   *<br>
+   * @retval 0 Success.<br>
+   * @retval non-zero Failed.<br>
+   */<br>
+  int ( *page_count )(<br>
+    rtems_flashdev *flashdev,<br>
+    int *page_count<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Call to device driver to return the minimum write size of the<br>
+   * flash device.<br>
+   *<br>
+   * @param[out] write_block_size The minimum write size of the flash device.<br>
+   *<br>
+   * @retval 0 Success.<br>
+   * @retval non-zero Failed.<br>
+   */<br>
+  int ( *write_block_size )(<br>
+    rtems_flashdev *flashdev,<br>
+    size_t *write_block_size<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Destroys the flash device.<br>
+   *<br>
+   * @param[in] flash Pointer to flash device.<br>
+   */<br>
+  void ( *destroy )(<br>
+    rtems_flashdev *flashdev<br>
+  );<br>
+<br>
+  /**<br>
+   * @brief Pointer to device driver.<br>
+   */<br>
+  void *driver;<br>
+<br>
+  /**<br>
+   * @brief Mutex to protect the flash device access.<br>
+   */<br>
+  rtems_recursive_mutex mutex;<br>
+<br>
+  /**<br>
+   * @brief Region table defining size and memory for region allocations<br>
+   */<br>
+  rtems_flashdev_region_table *region_table;<br>
+};<br>
+<br>
+/**<br>
+ * @brief Allocate and initialize the flash device.<br>
+ *<br>
+ * After a successful allocation and initialization of the flash device<br>
+ * it must be destroyed via rtems_flashdev_destroy_and_free().<br>
+ *<br>
+ * @param[in] size The number of bytes to allocate.<br>
+ *<br>
+ * @retval NULL Failed to set up flash device.<br>
+ * @retval non-NULL The new flash device.<br>
+ */<br>
+rtems_flashdev *rtems_flashdev_alloc_and_init(<br>
+  size_t size<br>
+);<br>
+<br>
+/**<br>
+ * @brief Initialize the flash device.<br>
+ *<br>
+ * After a successful initialization of the flash device it must be<br>
+ * destroyed via rtems_flashdev_destory().<br>
+ *<br>
+ * After initialization and before registration read, write, erase, jedec_id<br>
+ * and flash_type functions need to be set in the flashdev.<br>
+ *<br>
+ * @param[in] flash The flash device to initialize.<br>
+ *<br>
+ * @retval 1 Failed to set up flash device.<br>
+ * @retval 0 Successful set up of flash device.<br>
+ */<br>
+int rtems_flashdev_init(<br>
+  rtems_flashdev *flash<br>
+);<br>
+<br>
+/**<br>
+ * @brief Register the flash device.<br>
+ *<br>
+ * This function always claims ownership of the flash device.<br>
+ *<br>
+ * After initialization and before registration read, write, erase, jedec_id<br>
+ * and flash_type functions need to be set in the flashdev.<br>
+ *<br>
+ * @param[in] flash The flash device.<br>
+ * @param[in] flash_path The path to the flash device file.<br>
+ *<br>
+ * @retval 0 Successful operation.<br>
+ * @retval non-zero Failed operation.<br>
+ */<br>
+int rtems_flashdev_register(<br>
+  rtems_flashdev *flash,<br>
+  const char *flash_path<br>
+);<br>
+<br>
+/**<br>
+ * @brief Destroys the flash device.<br>
+ *<br>
+ * @param[in] flash The flash device.<br>
+ */<br>
+void rtems_flashdev_destroy(<br>
+  rtems_flashdev *flash<br>
+);<br>
+<br>
+/**<br>
+ * @brief Destroys the flash device and frees its memory.<br>
+ *<br>
+ * @param[in] flash The flash device.<br>
+ */<br>
+void rtems_flashdev_destroy_and_free(<br>
+  rtems_flashdev *flash<br>
+);<br>
+<br>
+/** @} */<br>
+<br>
+#endif /* _DEV_FLASHDEV_H */<br>
diff --git a/spec/build/cpukit/librtemscpu.yml b/spec/build/cpukit/librtemscpu.yml<br>
index 2c969aa5f6..86c5c8ff2b 100644<br>
--- a/spec/build/cpukit/librtemscpu.yml<br>
+++ b/spec/build/cpukit/librtemscpu.yml<br>
@@ -52,6 +52,9 @@ install:<br>
 - destination: ${BSP_INCLUDEDIR}/dev/spi<br>
   source:<br>
   - cpukit/include/dev/spi/spi.h<br>
+- destination: ${BSP_INCLUDEDIR}/dev/flash<br>
+  source:<br>
+  - cpukit/include/dev/flash/flashdev.h<br>
 - destination: ${BSP_INCLUDEDIR}/dev/can<br>
   source:<br>
   - cpukit/include/dev/can/can.h<br>
@@ -522,6 +525,7 @@ links:<br>
 - role: build-dependency<br>
   uid: vckey<br>
 source:<br>
+- cpukit/dev/flash/flashdev.c<br>
 - cpukit/dev/i2c/eeprom.c<br>
 - cpukit/dev/i2c/fpga-i2c-slave.c<br>
 - cpukit/dev/i2c/gpio-nxp-pca9535.c<br>
-- <br>
2.25.1<br>
<br>
_______________________________________________<br>
devel mailing list<br>
<a href="mailto:devel@rtems.org" target="_blank">devel@rtems.org</a><br>
<a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
</blockquote></div>