<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="zoom: 0%;">
<div dir="auto">Great, if you could add a note to that IOCTL to that effect before commit, that'd be great since consumers shouldn't rely on it to alter their consumption of the API. Otherwise, looks good to me!<br>
<br>
</div>
<div dir="auto">Kinsey </div>
<div class="gmail_quote">On Apr 23, 2023, at 21:45, Aaron Nyholm <<a href="mailto:aaron.nyholm@unfoldedeffective.com" target="_blank">aaron.nyholm@unfoldedeffective.com</a>> wrote:
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<pre class="blue">Yes, it is purely informational. It just returns the 3-byte JEDEC ID.<br><br>Regards,<br>Aaron.<br><br>------- Original Message -------<br>On Monday, April 24th, 2023 at 12:35 PM, Kinsey Moore <kinsey.moore@oarcorp.com> wrote:<br><br><br>
 <blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;">
   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).
  <br> 
  <br> Is this intended to be purely informational?
  <br> 
  <br> Kinsey
  <br> 
  <br> On Thu, Apr 20, 2023 at 2:23 AM <aaron.nyholm@unfoldedeffective.com> wrote:
  <br> 
  <br>
  <blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">
    From: Aaron Nyholm <aaron.nyholm@southerninnovation.com>
   <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>
   <hr>
   <br> devel mailing list
   <br> devel@rtems.org
   <br> 
   <a href="http://lists.rtems.org/mailman/listinfo/devel">http://lists.rtems.org/mailman/listinfo/devel</a>
   <br>
  </blockquote>
 </blockquote></pre>
</blockquote>
</div>
</body>
</html>