forked from Imagelibrary/rtems
This adds an API call allowing for unregistration to include destruction of private data that is not managed by the flashdev framework. This also updates the existing consumers of flashdev to use the new private data destructor callback.
322 lines
7.6 KiB
C
322 lines
7.6 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/*
|
|
* Copyright (C) 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.
|
|
*/
|
|
|
|
#include "test_flashdev.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <rtems/seterr.h>
|
|
|
|
#define TEST_DATA_SIZE (PAGE_SIZE * PAGE_COUNT)
|
|
#define PAGE_COUNT 16
|
|
#define PAGE_SIZE 128
|
|
#define SECTOR_COUNT 4
|
|
#define SECTOR_SIZE (TEST_DATA_SIZE / SECTOR_COUNT)
|
|
#define WB_SIZE 1
|
|
#define MAX_NUM_REGIONS 48
|
|
#define BITALLOC_SIZE 32
|
|
#define NUM_BITALLOC ((MAX_NUM_REGIONS + BITALLOC_SIZE - 1) / BITALLOC_SIZE)
|
|
|
|
/**
|
|
* This flash device driver is for testing flashdev
|
|
* API calls.
|
|
*/
|
|
typedef struct test_flashdev {
|
|
char* data;
|
|
uint32_t jedec_id;
|
|
uint32_t bit_allocator[NUM_BITALLOC];
|
|
rtems_flashdev_region regions[MAX_NUM_REGIONS];
|
|
} test_flashdev;
|
|
|
|
int test_flashdev_page_by_off(
|
|
rtems_flashdev *flash,
|
|
off_t search_offset,
|
|
off_t *page_offset,
|
|
size_t *page_size
|
|
);
|
|
|
|
int test_flashdev_page_by_index(
|
|
rtems_flashdev *flash,
|
|
off_t search_index,
|
|
off_t *page_offset,
|
|
size_t *page_size
|
|
);
|
|
|
|
int test_flashdev_page_count(
|
|
rtems_flashdev *flash,
|
|
int *page_count
|
|
);
|
|
|
|
int test_flashdev_wb_size(
|
|
rtems_flashdev *flash,
|
|
size_t *write_block_size
|
|
);
|
|
|
|
int test_flashdev_sector_by_off(
|
|
rtems_flashdev *flash,
|
|
off_t search_offset,
|
|
off_t *sector_offset,
|
|
size_t *sector_size
|
|
);
|
|
|
|
int test_flashdev_sector_count(
|
|
rtems_flashdev *flash,
|
|
int *sector_count
|
|
);
|
|
|
|
uint32_t test_flashdev_jedec_id(
|
|
rtems_flashdev* flash
|
|
);
|
|
|
|
int test_flashdev_type(
|
|
rtems_flashdev* flash,
|
|
rtems_flashdev_flash_type* type
|
|
);
|
|
|
|
int test_flashdev_read(
|
|
rtems_flashdev* flash,
|
|
uintptr_t offset,
|
|
size_t count,
|
|
void* buffer
|
|
);
|
|
|
|
int test_flashdev_write(
|
|
rtems_flashdev* flash,
|
|
uintptr_t offset,
|
|
size_t count,
|
|
const void* buffer
|
|
);
|
|
|
|
int test_flashdev_erase(
|
|
rtems_flashdev* flash,
|
|
uintptr_t offset,
|
|
size_t count
|
|
);
|
|
|
|
/* Find page info by offset handler */
|
|
int test_flashdev_page_by_off(
|
|
rtems_flashdev *flash,
|
|
off_t search_offset,
|
|
off_t *page_offset,
|
|
size_t *page_size
|
|
)
|
|
{
|
|
*page_offset = search_offset - (search_offset%PAGE_SIZE);
|
|
*page_size = PAGE_SIZE;
|
|
return 0;
|
|
}
|
|
|
|
/* Find page by index handler */
|
|
int test_flashdev_page_by_index(
|
|
rtems_flashdev *flash,
|
|
off_t search_index,
|
|
off_t *page_offset,
|
|
size_t *page_size
|
|
)
|
|
{
|
|
*page_offset = search_index * PAGE_SIZE;
|
|
*page_size = PAGE_SIZE;
|
|
return 0;
|
|
}
|
|
|
|
/* Page count handler */
|
|
int test_flashdev_page_count(
|
|
rtems_flashdev *flash,
|
|
int *page_count
|
|
)
|
|
{
|
|
*page_count = PAGE_COUNT;
|
|
return 0;
|
|
}
|
|
|
|
/* Write block size handler */
|
|
int test_flashdev_wb_size(
|
|
rtems_flashdev *flash,
|
|
size_t *write_block_size
|
|
)
|
|
{
|
|
*write_block_size = WB_SIZE;
|
|
return 0;
|
|
}
|
|
|
|
int test_flashdev_sector_by_off(
|
|
rtems_flashdev *flash,
|
|
off_t search_offset,
|
|
off_t *sector_offset,
|
|
size_t *sector_size
|
|
) {
|
|
*sector_offset = search_offset - (search_offset%SECTOR_SIZE);
|
|
*sector_size = SECTOR_SIZE;
|
|
return 0;
|
|
}
|
|
|
|
int test_flashdev_sector_count(
|
|
rtems_flashdev *flash,
|
|
int *sector_count
|
|
) {
|
|
*sector_count = SECTOR_COUNT;
|
|
return 0;
|
|
}
|
|
|
|
/* JEDEC ID handler, this would normally require a READID
|
|
* call to the physical flash device.
|
|
*/
|
|
uint32_t test_flashdev_jedec_id(
|
|
rtems_flashdev* flash
|
|
)
|
|
{
|
|
test_flashdev* driver = flash->driver;
|
|
return driver->jedec_id;
|
|
}
|
|
|
|
/* Function to identify what kind of flash is attached. */
|
|
int test_flashdev_type(
|
|
rtems_flashdev *flash,
|
|
rtems_flashdev_flash_type *type
|
|
)
|
|
{
|
|
*type = RTEMS_FLASHDEV_NOR;
|
|
return 0;
|
|
}
|
|
|
|
/* Read flash call. Any offset or count protections are
|
|
* required to be done in the driver function. */
|
|
int test_flashdev_read(
|
|
rtems_flashdev* flash,
|
|
uintptr_t offset,
|
|
size_t count,
|
|
void* buffer
|
|
)
|
|
{
|
|
test_flashdev* driver = flash->driver;
|
|
|
|
if (offset + count > TEST_DATA_SIZE) {
|
|
rtems_set_errno_and_return_minus_one( EINVAL );
|
|
}
|
|
|
|
memcpy(buffer, &driver->data[offset], count);
|
|
return 0;
|
|
}
|
|
|
|
/* Write Flash call. Any offset or count protections are
|
|
* required to be done in the driver function. */
|
|
int test_flashdev_write(
|
|
rtems_flashdev* flash,
|
|
uintptr_t offset,
|
|
size_t count,
|
|
const void* buffer
|
|
)
|
|
{
|
|
test_flashdev* driver = flash->driver;
|
|
|
|
if (offset + count > TEST_DATA_SIZE) {
|
|
rtems_set_errno_and_return_minus_one( EINVAL );
|
|
}
|
|
|
|
memcpy(&driver->data[offset], buffer, count);
|
|
return 0;
|
|
}
|
|
|
|
/* Erase Flash call. Any offset or count protections are
|
|
* required to be done in the driver function. */
|
|
int test_flashdev_erase(
|
|
rtems_flashdev* flash,
|
|
uintptr_t offset,
|
|
size_t count
|
|
)
|
|
{
|
|
test_flashdev* driver = flash->driver;
|
|
|
|
if (offset + count > TEST_DATA_SIZE) {
|
|
rtems_set_errno_and_return_minus_one( EINVAL );
|
|
}
|
|
|
|
if (offset%PAGE_SIZE || count%PAGE_SIZE) {
|
|
rtems_set_errno_and_return_minus_one( EINVAL );
|
|
}
|
|
|
|
memset(&driver->data[offset], 0, count);
|
|
return 0;
|
|
}
|
|
|
|
static void test_flashdev_priv_destroy(rtems_flashdev *flash)
|
|
{
|
|
test_flashdev* flash_driver = flash->driver;
|
|
free(flash_driver->data);
|
|
free(flash->driver);
|
|
free(flash->region_table);
|
|
}
|
|
|
|
/* Initialize Flashdev and underlying driver. */
|
|
rtems_flashdev* test_flashdev_init(void)
|
|
{
|
|
rtems_flashdev *flash = rtems_flashdev_alloc_and_init(sizeof(rtems_flashdev));
|
|
|
|
if (flash == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
test_flashdev* flash_driver = calloc(1, sizeof(test_flashdev));
|
|
|
|
if (flash_driver == NULL) {
|
|
rtems_flashdev_destroy_and_free(flash);
|
|
return NULL;
|
|
}
|
|
|
|
flash_driver->data = calloc(1, TEST_DATA_SIZE);
|
|
if (flash_driver->data == NULL) {
|
|
free(flash_driver);
|
|
rtems_flashdev_destroy_and_free(flash);
|
|
return NULL;
|
|
}
|
|
|
|
flash_driver->jedec_id = 0x00ABCDEF;
|
|
|
|
rtems_flashdev_region_table *ftable = calloc(1, sizeof(rtems_flashdev_region_table));
|
|
ftable->max_regions = MAX_NUM_REGIONS;
|
|
ftable->regions = flash_driver->regions;
|
|
ftable->bit_allocator = flash_driver->bit_allocator;
|
|
|
|
flash->driver = flash_driver;
|
|
flash->priv_destroy = &test_flashdev_priv_destroy;
|
|
flash->read = &test_flashdev_read;
|
|
flash->write = &test_flashdev_write;
|
|
flash->erase = &test_flashdev_erase;
|
|
flash->jedec_id = &test_flashdev_jedec_id;
|
|
flash->flash_type = &test_flashdev_type;
|
|
flash->page_info_by_offset = &test_flashdev_page_by_off;
|
|
flash->page_info_by_index = &test_flashdev_page_by_index;
|
|
flash->page_count = &test_flashdev_page_count;
|
|
flash->write_block_size = &test_flashdev_wb_size;
|
|
flash->sector_info_by_offset = &test_flashdev_sector_by_off;
|
|
flash->sector_count = &test_flashdev_sector_count;
|
|
flash->region_table = ftable;
|
|
|
|
return flash;
|
|
}
|