Files
levelx/common/src/fx_nand_flash_simulated_driver.c
T

438 lines
18 KiB
C

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
* Copyright (c) 2026-present Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** FileX NAND FLASH Simulator Driver */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary system files. */
#include "fx_api.h"
#include "lx_api.h"
/* Create a NAND flash control block. */
LX_NAND_FLASH nand_flash;
/* Memory buffer size should be at least 7 * total block count + 2 * page size,
that is 7 * 1024 + 2 * 528 = 8224 bytes */
ULONG lx_memory_buffer[8224 / sizeof (ULONG)];
/* Define the NAND flash simulation initialization function. */
UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash);
VOID _fx_nand_flash_read_sectors(ULONG logical_sector, ULONG sectors, UCHAR *destination_buffer);
VOID _fx_nand_flash_write_sectors(ULONG logical_sector, ULONG sectors, UCHAR *source_buffer);
/* The simulated NAND driver relies on the fx_media_format call to be made prior to
the fx_media_open call.
fx_media_format(&ram_disk,
_fx_nand_sim_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NAND_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
2048, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
*/
VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_nand_simulator_driver PORTABLE C */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is the entry point to the generic NAND simulated */
/* disk driver that is delivered with the flash wear leveling product */
/* LevelX. */
/* */
/* This driver also serves as a template for developing other LevelX */
/* NAND flash drivers for actual flash devices. Simply replace the */
/* read/write sector logic with calls to read/write from the */
/* appropriate physical device access functions. */
/* */
/* FileX NAND FLASH structures look like the following: */
/* */
/* Logical Sector Contents */
/* */
/* 0 Boot record */
/* 1 FAT Area Start */
/* +FAT Sectors Root Directory Start */
/* +Directory Sectors Data Sector Start */
/* */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_close Close NAND flash manager */
/* _lx_nand_flash_open Open NAND flash manager */
/* _lx_nand_flash_sector_read Read a NAND sector */
/* _lx_nand_flash_sector_release Release a NAND sector */
/* _lx_nand_flash_sector_write Write a NAND sector */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/**************************************************************************/
VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr)
{
ULONG logical_sector;
ULONG count;
UCHAR *buffer;
UINT status;
/* There are several useful/important pieces of information contained in the media
structure, some of which are supplied by FileX and others are for the driver to
setup. The following is a summary of the necessary FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_request FileX request type. Valid requests from FileX are
as follows:
FX_DRIVER_READ
FX_DRIVER_WRITE
FX_DRIVER_FLUSH
FX_DRIVER_ABORT
FX_DRIVER_INIT
FX_DRIVER_BOOT_READ
FX_DRIVER_RELEASE_SECTORS
FX_DRIVER_BOOT_WRITE
FX_DRIVER_UNINIT
fx_media_driver_status This value is RETURNED by the driver. If the
operation is successful, this field should be
set to FX_SUCCESS for before returning. Otherwise,
if an error occurred, this field should be set
to FX_IO_ERROR.
fx_media_driver_buffer Pointer to buffer to read or write sector data.
This is supplied by FileX.
fx_media_driver_logical_sector Logical sector FileX is requesting.
fx_media_driver_sectors Number of sectors FileX is requesting.
The following is a summary of the optional FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_info Pointer to any additional information or memory.
This is optional for the driver use and is setup
from the fx_media_open call. The RAM disk uses
this pointer for the RAM disk memory itself.
fx_media_driver_write_protect The DRIVER sets this to FX_TRUE when media is write
protected. This is typically done in initialization,
but can be done anytime.
fx_media_driver_free_sector_update The DRIVER sets this to FX_TRUE when it needs to
know when clusters are released. This is important
for FLASH wear-leveling drivers.
fx_media_driver_system_write FileX sets this flag to FX_TRUE if the sector being
written is a system sector, e.g., a boot, FAT, or
directory sector. The driver may choose to use this
to initiate error recovery logic for greater fault
tolerance.
fx_media_driver_data_sector_read FileX sets this flag to FX_TRUE if the sector(s) being
read are file data sectors, i.e., NOT system sectors.
fx_media_driver_sector_type FileX sets this variable to the specific type of
sector being read or written. The following sector
types are identified:
FX_UNKNOWN_SECTOR
FX_BOOT_SECTOR
FX_FAT_SECTOR
FX_DIRECTORY_SECTOR
FX_DATA_SECTOR
*/
/* Process the driver request specified in the media control block. */
switch(media_ptr -> fx_media_driver_request)
{
case FX_DRIVER_READ:
{
/* Read sector(s) from NAND flash. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
count = media_ptr -> fx_media_driver_sectors;
buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
while (count)
{
/* Call LevelX to read one flash sector. */
status = _lx_nand_flash_sector_read(&nand_flash, logical_sector, buffer);
/* Determine if the read was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful sector read. */
count--;
logical_sector++;
buffer += media_ptr -> fx_media_bytes_per_sector;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_WRITE:
{
/* Write sector(s) to NAND flash. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
count = media_ptr -> fx_media_driver_sectors;
buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
while (count)
{
/* Call LevelX to write a sector. */
status = _lx_nand_flash_sector_write(&nand_flash, logical_sector, buffer);
/* Determine if the write was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful sector write. */
count--;
logical_sector++;
buffer += media_ptr -> fx_media_bytes_per_sector;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_RELEASE_SECTORS:
{
/* Release the mapping of this sector. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
count = media_ptr -> fx_media_driver_sectors;
while (count)
{
/* Call LevelX to release a sector mapping. */
status = _lx_nand_flash_sector_release(&nand_flash, logical_sector);
/* Determine if the sector release was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful sector release. */
count--;
logical_sector++;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_FLUSH:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_ABORT:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_INIT:
{
/* FLASH drivers are responsible for setting several fields in the
media structure, as follows:
media_ptr -> fx_media_driver_free_sector_update
media_ptr -> fx_media_driver_write_protect
The fx_media_driver_free_sector_update flag is used to instruct
FileX to inform the driver whenever sectors are not being used.
This is especially useful for FLASH managers so they don't have
maintain mapping for sectors no longer in use.
The fx_media_driver_write_protect flag can be set anytime by the
driver to indicate the media is not writable. Write attempts made
when this flag is set are returned as errors. */
/* Perform basic initialization here... since the boot record is going
to be read subsequently and again for volume name requests. */
/* With flash wear leveling, FileX should tell wear leveling when sectors
are no longer in use. */
media_ptr -> fx_media_driver_free_sector_update = FX_TRUE;
/* Open the NAND flash simulation. */
status = _lx_nand_flash_open(&nand_flash, "sim nand flash", _lx_nand_flash_simulator_initialize, lx_memory_buffer, sizeof(lx_memory_buffer));
/* Determine if the flash open was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_UNINIT:
{
/* There is nothing to do in this case for the RAM driver. For actual
devices some shutdown processing may be necessary. */
/* Close the NAND flash simulation. */
status = _lx_nand_flash_close(&nand_flash);
/* Determine if the flash close was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_READ:
{
/* Read the boot record and return to the caller. */
status = _lx_nand_flash_sector_read(&nand_flash, 0, (UCHAR *) media_ptr -> fx_media_driver_buffer);
/* Determine if the read was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_WRITE:
{
/* Write the boot record and return to the caller. */
status = _lx_nand_flash_sector_write(&nand_flash, 0, (UCHAR *) media_ptr -> fx_media_driver_buffer);
/* Determine if the write was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break ;
}
default:
{
/* Invalid driver request. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
break;
}
}
}