incubator-nuttx/drivers/mtd/mtd_nandwrapper.c

420 lines
13 KiB
C

/****************************************************************************
* drivers/mtd/mtd_nandwrapper.c
* This deals with the wrapper over the upper half of the driver, to enable
* logging for debugging, and essentially passes the parameters right to the
* actual upper half of the NAND Flash device driver without changing them.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <assert.h>
#include <stddef.h>
#include <nuttx/config.h>
#include <nuttx/mtd/nand.h>
#include <nuttx/mtd/nand_ram.h>
#include <nuttx/mtd/nand_scheme.h>
#include <nuttx/mtd/nand_wrapper.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NAND_WRAPPER_DEBUG_1 1
#define NAND_WRAPPER_DEBUG_2 5
#define NAND_WRAPPER_DEBUG_3 10
#if CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL == 1
#define NAND_WRAPPER_DEBUG_LEVEL NAND_WRAPPER_DEBUG_1
#elif CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL == 2
#define NAND_WRAPPER_DEBUG_LEVEL NAND_WRAPPER_DEBUG_2
#elif CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL == 3
#define NAND_WRAPPER_DEBUG_LEVEL NAND_WRAPPER_DEBUG_3
#endif /* CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL */
#define NAND_WRAPPER_LOG(str, ...) \
{ \
if(nand_wrapper_ins_i % NAND_WRAPPER_DEBUG_LEVEL == 0) \
{ \
syslog(LOG_DEBUG, "nand_wrapper: " str, __VA_ARGS__); \
} \
}
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static uint64_t nand_wrapper_ins_i = 0; /* Instruction counter */
static mutex_t nand_wrapper_dev_mut;
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* External Functions
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nand_wrapper_erase
*
* Description:
* Wrapper for NAND MTD erase method.
*
* Input Parameters:
* dev: NAND MTD Device (with an actual type of `nand_wrapper_dev_s`
* startblock: Block number (0-indexing) to start erasing
* nblocks: Number of blocks to erase
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_erase(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Startblock: %" PRIi32
", N Blocks: %zu\n", nand_wrapper_ins_i, "erase",
startblock, nblocks);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.erase);
ret = nand_dev->under.mtd.erase(dev, startblock, nblocks);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Done\n",
nand_wrapper_ins_i, "erase");
}
else
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Failed: %" PRIi32 "!\n",
nand_wrapper_ins_i, "erase", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_bread
*
* Description:
* Wrapper for NAND MTD bread method.
*
* Input Parameters:
* dev: MTD Device
* startpage: Page number (0-indexing) to start reading
* npages: Number of pages to read.
* buffer: Preallocated memory where the data will be copied to
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
ssize_t nand_wrapper_bread(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR uint8_t *buffer)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] "
"Startblock: %" PRIi32 ", N Pages: %zu, Buffer: %p\n",
nand_wrapper_ins_i, "bread", startpage, npages, buffer);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.bread);
ret = nand_dev->under.mtd.bread(dev, startpage, npages, buffer);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Done\n",
nand_wrapper_ins_i, "bread");
}
else
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Failed: %" PRIi32 "!\n",
nand_wrapper_ins_i, "bread", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_bwrite
*
* Description:
* Wrapper for NAND MTD bwrite method.
*
* Input Parameters:
* dev: MTD Device
* startpage: Page number (0-indexing) to start reading
* npages: Number of pages to read.
* buffer: Data which will be written to the device
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes the length of `buffer` would be the same as the size of
* `npages * block_size`. This also assumes `dev` is specifically of
* type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
ssize_t nand_wrapper_bwrite(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR const uint8_t *buffer)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] "
"Startblock: %" PRIi32 ", N Pages: %zu, Buffer: %p\n",
nand_wrapper_ins_i, "bwrite", startpage, npages, buffer);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.bwrite);
ret = nand_dev->under.mtd.bwrite(dev, startpage, npages, buffer);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Done\n",
nand_wrapper_ins_i, "bwrite");
}
else
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Failed: %" PRIi32 "!\n",
nand_wrapper_ins_i, "bwrite", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_ioctl
*
* Description:
* Wrapper for NAND MTD ioctl method.
*
* Input Parameters:
* dev: MTD Device
* cmd: Command for IOCTL
* arg: Any argument required by command
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_ioctl(FAR struct mtd_dev_s *dev, int cmd,
unsigned long arg)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Command: %" PRIi32
", Arg : %zu\n", nand_wrapper_ins_i, "ioctl", cmd, arg);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.ioctl);
ret = nand_dev->under.mtd.ioctl(dev, cmd, arg);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Done\n",
nand_wrapper_ins_i, "ioctl");
}
else
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Failed: %" PRIi32 "!\n",
nand_wrapper_ins_i, "ioctl", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_isbad
*
* Description:
* Wrapper for NAND MTD isbad method.
*
* Input Parameters:
* dev: MTD Device
* block: Block number (0-indexing) to check if it is bad
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_isbad(FAR struct mtd_dev_s *dev, off_t block)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Block: %" PRIi32 "\n",
nand_wrapper_ins_i, "isbad", block);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.isbad);
ret = nand_dev->under.mtd.isbad(dev, block);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Done %" PRIi32 "\n",
nand_wrapper_ins_i, "isbad", ret);
}
else
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Failed: %" PRIi32 "!\n",
nand_wrapper_ins_i, "isbad", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_markbad
*
* Description:
* Wrapper for NAND MTD markbad method.
*
* Input Parameters:
* dev: MTD Device
* block: Block number (0-indexing) to mark it as bad
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_markbad(FAR struct mtd_dev_s *dev, off_t block)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Blocks: %" PRIi32 "\n",
nand_wrapper_ins_i, "markbad", block);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.markbad);
ret = nand_dev->under.mtd.markbad(dev, block);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Done\n",
nand_wrapper_ins_i, "markbad");
}
else
{
NAND_WRAPPER_LOG("[UPPER %" PRIu64 " | %s] Failed: %" PRIi32 "!\n",
nand_wrapper_ins_i, "markbad", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_initialize
*
* Description:
* Initializes wrapper.
*
* Returned Value:
* 0: Successful
* < 0: Error
*
****************************************************************************/
void nand_wrapper_initialize(void)
{
nxmutex_init(&nand_wrapper_dev_mut);
}