/**
 * \brief  Read the data and/or spare of a page of a NAND Flash chip, and verify
 * that the data is valid using the ECC information contained in the spare. If
 * one buffer pointer is 0, the corresponding area is not saved.
 *
 * \param ecc  Pointer to an nand_flash_ecc instance.
 * \param block  Number of block to read from.
 * \param page  Number of page to read inside given block.
 * \param data  Data area buffer.
 * \param spare  Spare area buffer.
 *
 * \return 0 if the data has been read and is valid; otherwise returns either
 * NAND_COMMON_ERROR_CORRUPTEDDATA or ...
 */
uint32_t nand_flash_ecc_read_page(const struct nand_flash_ecc *ecc,
		uint16_t block, uint16_t page, uint8_t *data, uint8_t *spare)
{
	uint32_t error;

	uint8_t hamming_code[NAND_COMMON_MAX_SPARE_ECC_BYTES];
	uint8_t spare_buffer[NAND_COMMON_MAX_PAGE_SPARE_SIZE];

	uint16_t page_data_size
		= nand_flash_model_get_page_data_size(MODEL(ecc));

	/* if no buffer provided, use a temp one */
	if (!spare) {
		spare = spare_buffer;
	}

	memset(spare, 0xFF, NAND_COMMON_MAX_PAGE_SPARE_SIZE);

	/* Start by reading the spare and the data */
	nand_flash_raw_read_page(RAW(ecc), block, page, data, spare);

	/* Retrieve ECC information from page and verify the data */
	nand_flash_spare_scheme_read_ecc(nand_flash_model_get_scheme(MODEL(ecc)),
			spare, hamming_code);
	error = hamming_verify_256x(data, page_data_size, hamming_code);
	if (error && (error != HAMMING_ERROR_SINGLE_BIT)) {
		return NAND_COMMON_ERROR_CORRUPTEDDATA;
	}

	return 0;
}
Exemple #2
0
//------------------------------------------------------------------------------
/// Initializes an EccNandFlash instance.
/// \param ecc  Pointer to an EccNandFlash instance.
/// \param model  Pointer to the underlying nand chip model. Can be 0.
/// \param commandAddress  Address at which commands are sent.
/// \param addressAddress  Address at which addresses are sent.
/// \param dataAddress  Address at which data is sent.
/// \param pinChipEnable  Pin controlling the CE signal of the NandFlash.
/// \param pinReadyBusy  Pin used to monitor the ready/busy signal of the Nand.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_Initialize(
    struct EccNandFlash *ecc,
    const struct NandFlashModel *model,
    unsigned int commandAddress,
    unsigned int addressAddress,
    unsigned int dataAddress,
    const Pin pinChipEnable,
    const Pin pinReadyBusy)
{
    unsigned char rc;
    rc = RawNandFlash_Initialize(RAW(ecc),
                                 model,
                                 commandAddress,
                                 addressAddress,
                                 dataAddress,
                                 pinChipEnable,
                                 pinReadyBusy);
#if defined(HARDWARE_ECC)
    {   unsigned int ecc_page;
        switch(NandFlashModel_GetPageDataSize(MODEL(ecc))) {
        case  512: ecc_page = AT91C_HSMC4_PAGESIZE_528_Bytes;  break;
        case 1024: ecc_page = AT91C_HSMC4_PAGESIZE_1056_Bytes; break;
        case 2048: ecc_page = AT91C_HSMC4_PAGESIZE_2112_Bytes; break;
        case 4096: ecc_page = AT91C_HSMC4_PAGESIZE_4224_Bytes; break;
        default:
            TRACE_ERROR("PageSize %d not compatible with ECC\n\r",
                        NandFlashModel_GetPageDataSize(MODEL(ecc)));
            return NandCommon_ERROR_ECC_NOT_COMPATIBLE;
        }
        HSMC4_EccConfigure(AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES,
                           ecc_page);
    }
#endif
    return rc;
}
/**
 * \brief  Reads the data and/or the spare area of a page on a translated nandflash.
 * If the block is not currently mapped but could be (i.e. there are available
 * physical blocks), then the data/spare is filled with 0xFF.
 *
 * \param translated  Pointer to a TranslatedNandFlash instance.
 * \param block  Logical block number.
 * \param page  Number of page to read inside logical block.
 * \param data  Data area buffer, can be 0.
 * \param spare  Spare area buffer, can be 0.
 * \return 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS
 */
unsigned char TranslatedNandFlash_ReadPage( const struct TranslatedNandFlash *translated, unsigned short block,
                                            unsigned short page, void *data, void *spare )
{
    unsigned char error ;

    TRACE_INFO("TranslatedNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);

    /* If the page to read is in the current block, there is a previous physical
       block and the page is clean -> read the page in the old block since the
       new one does not contain meaningful data*/
    if ( (block == translated->currentLogicalBlock) && (translated->previousPhysicalBlock != -1)
         && (PageIsClean(translated, page)) )
    {
        TRACE_DEBUG("Reading page from current block\n\r");
        return ManagedNandFlash_ReadPage( MANAGED( translated ), translated->previousPhysicalBlock,
                                          page, data, spare ) ;
    }
    else
    {
        /* Try to read the page from the logical block*/
        error = MappedNandFlash_ReadPage(MAPPED(translated), block, page, data, spare);

        /* Block was not mapped*/
        if ( error == NandCommon_ERROR_BLOCKNOTMAPPED )
        {
            assert( !spare ) ; /* "Cannot read the spare information of an unmapped block\n\r" */

            /* Check if a block can be allocated*/
            if ( BlockCanBeAllocated( translated ) )
            {
                /* Return 0xFF in buffers with no error*/
                TRACE_DEBUG("Block #%d is not mapped but can be allocated, filling buffer with 0xFF\n\r", block);
                if (data)
                {
                    memset(data, 0xFF, NandFlashModel_GetPageDataSize(MODEL(translated)));
                }
                if (spare)
                {
                    memset(spare, 0xFF, NandFlashModel_GetPageSpareSize(MODEL(translated)));
                }
            }
            else
            {
                TRACE_ERROR("Block #%d is not mapped and there are no more blocks available\n\r", block);
                return NandCommon_ERROR_NOMOREBLOCKS;
            }
        }
        /* Error*/
        else
        {
            if (error)
            {
                return error;
            }
        }
    }

    return 0;
}
Exemple #4
0
/**
 * \brief Sends the column address to the NandFlash chip.
 *
 * \param raw  Pointer to a RawNandFlash instance.
 * \param columnAddress  Column address to send.
 */
static void WriteColumnAddress(
    const struct RawNandFlash *raw,
    unsigned short columnAddress)
{
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));

    /* Check the data bus width of the NandFlash */
    if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
        /* Div 2 is because we address in word and not in byte */
        columnAddress >>= 1;
    }
Exemple #5
0
int			sp_loadconf_models(t_env *e)
{
	t_model const		tmp[sp_num_models] = {

	MODEL(sp_main_mesh, sp_porcelain_texture, &sp_unif_model_mix),
	MODEL(sp_plane_mesh, sp_wall_texture, &sp_unif_model),
	MODEL(sp_land_mesh, sp_no_texture, NULL),
	MODEL(sp_sun_mesh, sp_no_texture, &sp_unif_model),
	};
	memcpy(&e->models, &tmp, sizeof(tmp));
	return (0);
}
/**
 * \brief Translate the given column and row address into first and other (1-4)
 * address cycles. The resulting values are stored in the provided variables
 * if they are not null.
 *
 * \param raw  Pointer to a nand_flash_raw instance.
 * \param column_address  Column address to translate.
 * \param row_address  Row address to translate.
 * \param p_address_cycle0  First address cycle.
 * \param p_address_cycle1234 four address cycles.
 * \param five_address Flag for five address cycles.
 */
static void nfc_translate_address(const struct nand_flash_raw *raw,
		uint32_t column_address, uint32_t row_address,
		uint32_t *p_address_cycle0, uint32_t *p_address_cycle1234,
		uint32_t five_address)
{
	uint16_t page_data_size = nand_flash_model_get_page_data_size(MODEL(raw));
	uint32_t num_page =	nand_flash_model_get_device_size_in_pages(MODEL(raw));
	uint32_t address_cycles = 0;
	uint32_t address_cycle0 = 0;
	uint32_t address_cycle1234 = 0;

	/* Check the data bus width of the NAND Flash */
	if (nand_flash_model_get_data_bus_width(MODEL(raw)) == 16) {
		/* Div 2 is because we address in word and not in byte */
		column_address >>= 1;
	}
Exemple #7
0
//------------------------------------------------------------------------------
/// Copies the data from a whole block to another block on a nandflash. Both
/// blocks must be LIVE.
/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if
/// at least one of the blocks is not free, or a NandCommon_ERROR_xxx code.
/// \param managed  Pointer to a ManagedNandFlash instance.
/// \param sourceBlock  Source block number.
/// \param destBlock  Destination block number.
//------------------------------------------------------------------------------
unsigned char ManagedNandFlash_CopyBlock(
    const struct ManagedNandFlash *managed,
    unsigned short sourceBlock,
    unsigned short destBlock)
{
    unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(managed));
    unsigned char error;
    unsigned short page;

    ASSERT(sourceBlock != destBlock,
           "ManagedNandFlash_CopyBlock: Source block must be different from dest. block\n\r");

    TRACE_INFO("ManagedNandFlash_CopyBlock(B#%d->B#%d)\n\r",
              sourceBlock, destBlock);

    // Copy all pages
    for (page=0; page < numPages; page++) {

        error = ManagedNandFlash_CopyPage(managed,
                                          sourceBlock,
                                          page,
                                          destBlock,
                                          page);
        if (error) {

            TRACE_ERROR("ManagedNandFlash_CopyPage: Failed to copy page %d\n\r", page);
            return error;
        }
    }

    return 0;
}
Exemple #8
0
/**
 * \brief This function transfers the USB MSC data to the memory
 *
 * \param addr Sector address to start write
 * \param nb_sector Number of sectors to transfer (sector=512 bytes)
 *
 * \return Ctrl_status
 */
Ctrl_status nand_flash_usb_write_10(uint32_t addr, uint16_t nb_sector)
{
	uint8_t nb_sector_trans;
	uint16_t page_data_size
		= nand_flash_model_get_page_data_size(MODEL(&nf_translation));

	if (nand_flash_status == NAND_FLASH_READY) {
		while (nb_sector) {
			nb_sector_trans
				= min(nb_sector,
					(page_data_size / SECTOR_SIZE));
			udi_msc_trans_block(false,
					(uint8_t *)nand_flash_usb_buffer,
					(nb_sector_trans * SECTOR_SIZE), NULL);
			if (nand_flash_write((addr * SECTOR_SIZE),
					nand_flash_usb_buffer,
					(nb_sector_trans * SECTOR_SIZE))) {
				return CTRL_FAIL;
			}

			nb_sector -= nb_sector_trans;
			addr += nb_sector_trans;
		}
		return CTRL_GOOD;
	}

	return CTRL_BUSY;
}
/**
 * \brief  Read the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to read.
 * \param pageOffsetInBlock  Number of the page to read inside the given block.
 * \param data  Data area buffer.
 * \param numPages  number of pages to read.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
uint8_t SkipBlockNandFlash_ReadBlockUnaligned(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    uint16_t pageOffsetInBlock,
    uint16_t numPages,
    void *data
    )
{
    /* Page size*/
    uint32_t pageSize;
    /* Page index*/
    uint16_t i;
    /* Error returned by SkipBlockNandFlash_ReadPage*/
    uint8_t error = 0;

    /* Retrieve model information*/
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));

    for (i = pageOffsetInBlock; i < pageOffsetInBlock + numPages; i++) {
        error = SkipBlockNandFlash_ReadPage(skipBlock, block, i, data, 0);
        if (error == NandCommon_ERROR_BADBLOCK) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
            return NandCommon_ERROR_BADBLOCK;
        }
        else if (error) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
            return NandCommon_ERROR_CANNOTREAD;
        }
        data = (void *) ((uint8_t *) data + pageSize);
    }

    return 0;
}
Exemple #10
0
static void 
icontainer_real_current( iContainer *parent, iContainer *child )
{
	iContainer *old_current;

	g_assert( IS_ICONTAINER( parent ) );
	g_assert( !child || IS_ICONTAINER( child ) );
	g_assert( !child || ICONTAINER_IS_CHILD( parent, child ) );

#ifdef DEBUG
	printf( "icontainer_real_current: parent %s \"%s\"; "
		"child %s \"%s\"\n", 
		G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ),
		child ? G_OBJECT_TYPE_NAME( child ) : "NULL", 
		child ? NN( IOBJECT( child )->name ) : "NULL" );
#endif /*DEBUG*/

	old_current = parent->current;
	parent->current = child;

	if( old_current != child ) {
		if( old_current )
			iobject_changed( IOBJECT( old_current ) );
		if( child )
			iobject_changed( IOBJECT( child ) );
		iobject_changed( IOBJECT( parent ) );
	}

	if( child )
		model_front( MODEL( child ) );
}
/**
 * \brief Check the given page inside the currently written block is clean or not.
 *
 * \param translated  Pointer to a TranslatedNandFlash instance.
 * \param page  Page number.
 * \return 1 if the given page inside the currently written block is clean (has
 * not been written yet); otherwise returns 0.
 */
static unsigned char PageIsClean(
    const struct TranslatedNandFlash *translated,
    unsigned short page)
{
    assert( page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)) ) ; /* "PageIsClean: Page out-of-bounds\n\r" */

    return ((translated->currentBlockPageStatuses[page / 8] >> (page % 8)) & 1) == 0;
}
/**
 * \brief Marks the given page as being dirty (i.e. written).
 *
 * \param translated  Pointer to a TranslatedNandFlash instance.
 * \param page  Page number.
 */
static void MarkPageDirty(
    struct TranslatedNandFlash *translated,
    unsigned short page)
{
    assert( page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)) ) ; /* "PageIsClean: Page out-of-bounds\n\r" */

    translated->currentBlockPageStatuses[page / 8] |= 1 << (page % 8);
}
Exemple #13
0
//------------------------------------------------------------------------------
/// Reads the data and/or spare of a page of a nandflash chip, and verify that
/// the data is valid using the ECC information contained in the spare. If one
/// buffer pointer is 0, the corresponding area is not saved.
/// Returns 0 if the data has been read and is valid; otherwise returns either
/// NandCommon_ERROR_CORRUPTEDDATA or ...
/// \param ecc  Pointer to an EccNandFlash instance.
/// \param block  Number of block to read from.
/// \param page  Number of page to read inside given block.
/// \param data  Data area buffer.
/// \param spare  Spare area buffer.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_ReadPage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char tmpData[NandCommon_MAXPAGEDATASIZE];
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned char error;
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));

    TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);

    // Start by reading the spare and the data
    error = RawNandFlash_ReadPage(RAW(ecc), block, page, tmpData, tmpSpare);
    if (error) {

        TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
        return error;
    }

    // Retrieve ECC information from page and verify the data
    NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming);
    error = Hamming_Verify256x(tmpData, pageDataSize, hamming);
    if (error && (error != Hamming_ERROR_SINGLEBIT)) {

        TRACE_ERROR("EccNandFlash_ReadPage: Unrecoverable data\n\r");
        return NandCommon_ERROR_CORRUPTEDDATA;
    }

    // Copy data and/or spare into final buffers
    if (data) {

        memcpy(data, tmpData, pageDataSize);
    }
    if (spare) {

        memcpy(spare, tmpSpare, pageSpareSize);
    }

    return 0;
}
Exemple #14
0
//------------------------------------------------------------------------------
/// Writes the data and/or spare area of a nandflash page, after calculating an
/// ECC for the data area and storing it in the spare. If no data buffer is
/// provided, the ECC is read from the existing page spare. If no spare buffer
/// is provided, the spare area is still written with the ECC information
/// calculated on the data buffer.
/// Returns 0 if successful; otherwise returns an error code.
/// \param ecc Pointer to an EccNandFlash instance.
/// \param block  Number of the block to write in.
/// \param page  Number of the page to write inside the given block.
/// \param data  Data area buffer, can be 0.
/// \param spare  Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char EccNandFlash_WritePage(
    const struct EccNandFlash *ecc,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    unsigned char error;
    unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
    unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
    unsigned char hamming[NandCommon_MAXSPAREECCBYTES];

    ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r");
    TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);

    // Compute ECC on the new data, if provided
    // If not provided, hamming code set to 0xFFFF.. to keep existing bytes
    memset(hamming, 0xFF, NandCommon_MAXSPAREECCBYTES);
    if (data) {

        // Compute hamming code on data
        Hamming_Compute256x(data, pageDataSize, hamming);
    }

    // Store code in spare buffer (if no buffer provided, use a temp. one)
    if (!spare) {

        spare = tmpSpare;
        memset(spare, 0xFF, pageSpareSize);
    }
    NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hamming);

    // Perform write operation
    error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
    if (error) {

        TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
        return error;
    }

    return 0;
}
//------------------------------------------------------------------------------
/// Translates the given column and row address into first and other (1-4) address
/// cycles. The resulting values are stored in the provided variables if they are not null.
/// \param columnAddress  Column address to translate.
/// \param rowAddress  Row address to translate.
/// \param pAddressCycle0  First address cycle.
/// \param pAddressCycle1234 four address cycles.
//------------------------------------------------------------------------------
void NFC_TranslateAddress(
    const struct RawNandFlash *raw,
    unsigned short columnAddress,
    unsigned int rowAddress,
    unsigned int *pAddressCycle0,
    unsigned int *pAddressCycle1234,
    unsigned char useFiveAddress)
{
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
    unsigned int numPages = NandFlashModel_GetDeviceSizeInPages(MODEL(raw));
    unsigned char numAddressCycles = 0;
    unsigned int addressCycle0 = 0;
    unsigned int addressCycle1234 = 0;
    
    // Check the data bus width of the NandFlash 
    if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
        // Div 2 is because we address in word and not in byte 
        columnAddress >>= 1;
    }
/**
 * \brief  Write the data and/or spare area of a NAND Flash page, after
 * calculating an ECC for the data area and storing it in the spare. If no
 * data buffer is provided, the ECC is read from the existing page spare. If
 * no spare buffer is provided, the spare area is still written with the ECC
 * information calculated on the data buffer.
 *
 * \param ecc  Pointer to an nand_flash_ecc instance.
 * \param block  Number of block to read from.
 * \param page  Number of page to read inside given block.
 * \param data  Data area buffer.
 * \param spare  Spare area buffer.
 *
 * \return 0 if successful; otherwise return the error code.
 */
uint32_t nand_flash_ecc_write_page(const struct nand_flash_ecc *ecc,
		uint16_t block, uint16_t page, uint8_t *data, uint8_t *spare)
{
	uint32_t error;

	uint16_t page_data_size
		= nand_flash_model_get_page_data_size(MODEL(ecc));

	uint8_t hamming_code[NAND_COMMON_MAX_SPARE_ECC_BYTES];
	uint8_t spare_buffer[NAND_COMMON_MAX_PAGE_SPARE_SIZE];

	/**
	 * Compute ECC on the new data, if provided. If not provided, hamming
	 * code set to 0xFFFF.. to keep existing bytes.
	 */
	memset(hamming_code, 0xFF, NAND_COMMON_MAX_SPARE_ECC_BYTES);
	if (data) {
		/* Compute hamming code on data */
		hamming_compute_256x(data, page_data_size, hamming_code);
	}

	/* if no buffer provided, use a temp one */
	if (!spare) {
		spare = spare_buffer;
	}

	memset(spare, 0xFF, NAND_COMMON_MAX_PAGE_SPARE_SIZE);

	nand_flash_spare_scheme_write_ecc(nand_flash_model_get_scheme(MODEL(ecc)),
			spare, hamming_code);

	/* Perform write operation */
	error = nand_flash_raw_write_page(RAW(ecc), block, page, data, spare);
	if (error) {
		return error;
	}

	return 0;
}
/**
 * \brief  Read the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to read.
 * \param pageOffsetInBlock  Number of the page to read inside the given block.
 * \param data  Data area buffer.
 * \param numPages  number of pages to read.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
unsigned char SkipBlockNandFlash_ReadBlockUnaligned(
    const struct SkipBlockNandFlash *skipBlock,
    unsigned short block,
    unsigned short pageOffsetInBlock,
    unsigned short numPages,
    void *data
    )
{
    /* Number of pages per block*/
    unsigned int numPagesPerBlock;
    /* Page size*/
    unsigned int pageSize;
    /* Page index*/
    unsigned short i;
    /* Error returned by SkipBlockNandFlash_ReadPage*/
    unsigned char error = 0;

    /* Retrieve model information*/
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
    numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));

    for (i = pageOffsetInBlock; i < pageOffsetInBlock + numPages; i++) {
        error = SkipBlockNandFlash_ReadPage(skipBlock, block, i, data, 0);
        if (error == NandCommon_ERROR_BADBLOCK) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
            return NandCommon_ERROR_BADBLOCK;
        }
        else if (error) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
            return NandCommon_ERROR_CANNOTREAD;
        }
        data = (void *) ((unsigned char *) data + pageSize);
    }

    return 0;
}
/**
 * \brief Writes the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to write.
 * \param data  Data area buffer.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
uint8_t SkipBlockNandFlash_WriteBlock(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    void *data)
{
    /* Number of pages per block */
    uint32_t numPagesPerBlock;
    /* Page size */
    uint32_t pageSize;
    /* Page index*/
    uint16_t i;
    /* Error returned by SkipBlockNandFlash_WritePage*/
    uint8_t error = 0;

    /* Retrieve model information*/
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
    numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));

    /* Check that the block is LIVE*/
    if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

        TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Block is BAD.\n\r");
        return NandCommon_ERROR_BADBLOCK;
    }

    for (i = 0; i < numPagesPerBlock; i++) {
        error = EccNandFlash_WritePage(ECC(skipBlock), block, i, data, 0);
        if (error) {

            TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block);
            return NandCommon_ERROR_CANNOTWRITE;
        }
        data = (void *) ((uint8_t *) data + pageSize);
    }

    return 0;
}
Exemple #19
0
static void
prefs_build( GtkWidget *widget )
{
	Prefs *prefs = PREFS( widget );
	GtkWidget *work;

#ifdef DEBUG
	printf( "prefs_build: %p\n", prefs );
#endif /*DEBUG*/

	/* Call all builds in superclasses.
	 */
	IWINDOW_CLASS( parent_class )->build( widget );

	work = IDIALOG( prefs )->work;

	prefs->pwview = PREFWORKSPACEVIEW( prefworkspaceview_new() );
	prefworkspaceview_set_caption_filter( prefs->pwview, 
		prefs->caption_filter );
	view_link( VIEW( prefs->pwview ), MODEL( prefs->ws ), NULL );

	if( prefs->caption_filter ) {
		gtk_box_pack_start( GTK_BOX( work ), 
			GTK_WIDGET( prefs->pwview ), TRUE, TRUE, 0 );

		gtk_widget_show( GTK_WIDGET( prefs->pwview ) );
	}
	else {
		/* No caption_filter set, so this is probably a big prefs
		 * window. Build a scrolledwindow for the content.
		 */
		GtkWidget *window;

		window = gtk_scrolled_window_new( NULL, NULL );
		gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( window ), 
			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
		gtk_scrolled_window_add_with_viewport( 
			GTK_SCROLLED_WINDOW( window ), 
			GTK_WIDGET( prefs->pwview ) );
		gtk_viewport_set_shadow_type( 
			GTK_VIEWPORT( GTK_BIN( window )->child ), 
			GTK_SHADOW_NONE );
		gtk_box_pack_start( GTK_BOX( work ), 
			GTK_WIDGET( window ), TRUE, TRUE, 0 );

		gtk_widget_show( GTK_WIDGET( prefs->pwview ) );
		gtk_widget_show( window );
	}
}
/**
 * \brief Reads the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of block to read page from.
 * \param page  Number of page to read inside the given block.
 * \param data  Data area buffer, can be 0.
 * \param spare  Spare area buffer, can be 0.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage().
 */
unsigned char SkipBlockNandFlash_ReadBlock(
    const struct SkipBlockNandFlash *skipBlock,
    unsigned short block,
    void *data)
{
    /* Number of pages per block */
    unsigned int numPagesPerBlock, pageSize;
    /* Page index */
    unsigned short i;
    /* Error returned by SkipBlockNandFlash_WritePage */
    unsigned char error = 0;

    /* Retrieve model information */
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
    numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));

    /* Check that the block is not BAD if data is requested */
    if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

        TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
        return NandCommon_ERROR_BADBLOCK;
    }

    /* Read all the pages of the block */
    for (i = 0; i < numPagesPerBlock; i++) {
        error = EccNandFlash_ReadPage(ECC(skipBlock), block, i, data, 0);
        if (error) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
            return error;
        }
        data = (void *) ((unsigned char *) data + pageSize);
    }

    return 0;
}
Exemple #21
0
//------------------------------------------------------------------------------
/// Returns BADBLOCK if the given block of a nandflash device is bad; returns
/// GOODBLOCK if the block is good; or returns a NandCommon_ERROR code.
/// \param managed  Pointer to a ManagedNandFlash instance.
/// \param block    Raw block to check.
/// \param spare    Pointer to allocated spare area (must be assigned)
//------------------------------------------------------------------------------
static unsigned char CheckBlock(
    const struct ManagedNandFlash *managed,
    unsigned short block,
    unsigned char  *spare)
{
    unsigned char error;
    unsigned int i;
    unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed));

    ASSERT(spare, "ManagedNandFlash_CheckBlock: spare\n\r");

    // Read spare area of first page of block
    error = RawNandFlash_ReadPage(RAW(managed), block, 0, 0, spare);
    if (error) {

        TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block);
        return error;
    }

    // Make sure it is all 0xFF
    for (i=0; i < pageSpareSize; i++) {

        if (spare[i] != 0xFF) {

            return BADBLOCK;
        }
    }

    // Read spare area of second page of block
    error = RawNandFlash_ReadPage(RAW(managed), block, 1, 0, spare);
    if (error) {

        TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block);
        return error;
    }

    // Make sure it is all 0xFF
    for (i=0; i < pageSpareSize; i++) {

        if (spare[i] != 0xFF) {

            return BADBLOCK;
        }
    }

    return GOODBLOCK;
}
Exemple #22
0
//------------------------------------------------------------------------------
/// Physically writes the status of a block inside its first page spare area.
/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xx code.
/// \param managed  Pointer to a ManagedNandFlash instance.
/// \param block    Raw block number.
/// \param pStatus  Pointer to status data.
/// \param spare    Pointer to allocated spare area (must be assigned).
//------------------------------------------------------------------------------
static unsigned char WriteBlockStatus(
    const struct ManagedNandFlash *managed,
    unsigned short block,
    struct NandBlockStatus *pStatus,
    unsigned char *spare)
{
    ASSERT(spare, "ManagedNandFlash_WriteBlockStatus: spare\n\r");

    memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE);
    NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)),
                               spare,
                               pStatus,
                               4,
                               0);
    return RawNandFlash_WritePage(RAW(managed),
                                  block, 0, 0, spare);
}
Exemple #23
0
uint8_t SkipBlockNandFlash_CheckBlock(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block)
{

#if !defined (OP_BOOTSTRAP_on)
    uint8_t spare[NandCommon_MAXPAGESPARESIZE];
    uint8_t error;
    uint8_t badBlockMarker;
    const struct NandSpareScheme *scheme;


    /* Retrieve model scheme */
    scheme = NandFlashModel_GetScheme(MODEL(skipBlock));
    
    /* Read spare area of first page of block */
    error = RawNandFlash_ReadPage(RAW(skipBlock), block, 0, 0, spare);
    if (error) {

        TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block);
        return error;
    }

    NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
    if (badBlockMarker != 0xFF) {

        return BADBLOCK;
    }

    /* Read spare area of second page of block */
    error = RawNandFlash_ReadPage(RAW(skipBlock), block, 1, 0, spare);
    if (error) {

        TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block);
        return error;
    }

    NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
    if (badBlockMarker != 0xFF) {

        return BADBLOCK;
    }
#endif

    return GOODBLOCK;
}
/**
 * \brief  Terminates the current write operation by copying all the missing pages from
 * the previous physical block.
 *
 * \param translated  Pointer to a TranslatedNandFlash instance.
 * \return 0 if successful; otherwise returns error code
 */
unsigned char TranslatedNandFlash_Flush(struct TranslatedNandFlash *translated)
{
    unsigned int i;
    unsigned char error;
    unsigned int currentPhysicalBlock;

    /* Check if there is a current block and a previous block*/
    if ((translated->currentLogicalBlock == -1)
        || (translated->previousPhysicalBlock == -1))
    {
        return 0;
    }

    TRACE_INFO("TranslatedNandFlash_Flush(PB#%d -> LB#%d)\n\r",
              translated->previousPhysicalBlock, translated->currentLogicalBlock);

    /* Copy missing pages in the current block*/
    currentPhysicalBlock = MappedNandFlash_LogicalToPhysical(
                                MAPPED(translated),
                                translated->currentLogicalBlock);

    for (i=0; i < NandFlashModel_GetBlockSizeInPages(MODEL(translated)); i++)
    {
        if (PageIsClean(translated, i))
        {
            TRACE_DEBUG("Copying back page #%d of block #%d\n\r", i, translated->previousPhysicalBlock);

            /* Copy page*/
            error = ManagedNandFlash_CopyPage(MANAGED(translated),
                                              translated->previousPhysicalBlock,
                                              i,
                                              currentPhysicalBlock,
                                              i);
            if (error)
            {
                TRACE_ERROR("FinishCurrentWrite: copy page #%d\n\r", i);
                return error;
            }
        }
    }

    translated->currentLogicalBlock = -1;
    translated->previousPhysicalBlock = -1;
    return 0;
}
Exemple #25
0
//------------------------------------------------------------------------------
/// Returns 1 if a nandflash device is virgin (i.e. has never been used as a
/// managed nandflash); otherwise return 0.
/// \param managed  Pointer to a ManagedNandFlash instance.
/// \param spare    Pointer to allocated spare area (must be assigned)
//------------------------------------------------------------------------------
static unsigned char IsDeviceVirgin(const struct ManagedNandFlash *managed,
                                    unsigned char *spare)
{
    struct NandBlockStatus blockStatus;
    const struct NandSpareScheme *scheme =
                            NandFlashModel_GetScheme(MODEL(managed));
    unsigned short baseBlock = managed->baseBlock;
    unsigned char badBlockMarker;
    
    unsigned char error;

    ASSERT(spare, "ManagedNandFlash_IsDeviceVirgin: spare\n\r");

    // Read spare area of page #0
    error = RawNandFlash_ReadPage(RAW(managed), baseBlock, 0, 0, spare);
    ASSERT(!error, "ManagedNandFlash_IsDeviceVirgin: Failed to read page #0\n\r");

    // Retrieve bad block marker and block status from spare area
    NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
    NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0);

    // Check if block is marked as bad
    if (badBlockMarker != 0xFF) {

        // Device is not virgin, since page #0 is guaranteed to be good
        return 0;
    }
    // If device is not virgin, then block status will be set to either
    // FREE, DIRTY or LIVE
    else if (blockStatus.status != NandBlockStatus_DEFAULT) {

        // Device is not virgin
        return 0;
    }

    return 1;
}
/**
 * \brief Erases a block of a SkipBlock NandFlash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of block to erase.
 * \return the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS.
 */
uint8_t SkipBlockNandFlash_EraseBlock(
    struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    uint32_t eraseType)
{
    uint8_t error;
    const struct NandSpareScheme *scheme;
    uint8_t spare[NandCommon_MAXPAGESPARESIZE];

    // TRACE_INFO("SkipBlockNandFlash_EraseBlock(%d)\n\r", block);

    if (eraseType != SCRUB_ERASE) {
        /* Check block status */
        if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

            TRACE_INFO("SkipBlockNandFlash_EraseBlock: Block is BAD\n\r");
            return NandCommon_ERROR_BADBLOCK;
        }
    }

    /* Erase block */
    error = RawNandFlash_EraseBlock(RAW(skipBlock), block);
    if (error) {

        /* Try to mark the block as BAD */
        TRACE_ERROR("SkipBlockNandFlash_EraseBlock: Cannot erase block, try to mark it BAD\n\r");

        /* Retrieve model scheme */
        scheme = NandFlashModel_GetScheme(MODEL(skipBlock));

        memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE);
        NandSpareScheme_WriteBadBlockMarker(scheme, spare, NandBlockStatus_BAD_skip);
        return RawNandFlash_WritePage(RAW(skipBlock), block, 0, 0, spare);
    }

    return 0;
}
Exemple #27
0
/**
 * This function is called when the control program is loaded to zenom.
 * Use this function to register control parameters, to register log variables
 * and to initialize control parameters.
 *
 * @return Return non-zero to indicate an error.
 */
int ZenomMatlab::initialize()
{
    
    int paramIdx, sigIdx;
    int nBlockParams, nSignals;
    const char* status;
    
    // İsmi gözükmeyen parametrelerin sayısını tutar.
    unknown_param_counter = 0;

    /* Here is where Q8 dirver is  loaded to kernel space */
     
    //system(STR(sudo insmod DQ8));
    fd = rt_dev_open(DEV_NAME, O_RDWR);

    if(fd < 0)
        fprintf(stderr, "target:Q8 device open error!\n");
    
    
    init_xenomai();

    rtM = MODEL();

    if (rtmGetErrorStatus(rtM) != NULL) {
        (void)fprintf(stderr,"Error during model registration: %s\n",
                      rtmGetErrorStatus(rtM));
        exit(EXIT_FAILURE);
    }
    
    MdlInitializeSizes();
    MdlInitializeSampleTimes();

    status = rt_SimInitTimingEngine(rtmGetNumSampleTimes(rtM),
                                    rtmGetStepSize(rtM),
                                    rtmGetSampleTimePtr(rtM),
                                    rtmGetOffsetTimePtr(rtM),
                                    rtmGetSampleHitPtr(rtM),
                                    rtmGetSampleTimeTaskIDPtr(rtM),
                                    rtmGetTStart(rtM),
                                    &rtmGetSimTimeStep(rtM),
                                    &rtmGetTimingData(rtM));


    if (status != NULL) {
        (void)fprintf(stderr, "Failed to initialize sample time engine: %s\n", status);
        exit(EXIT_FAILURE);
    }

    rt_CreateIntegrationData(rtM);

    mmi = &(rtmGetDataMapInfo(rtM).mmi);

    if (mmi!=NULL){
        //exception here 
    }    

    bp = rtwCAPI_GetBlockParameters(mmi);
    sig = rtwCAPI_GetSignals(mmi);

    nBlockParams = rtwCAPI_GetNumBlockParameters(mmi);
    nSignals = rtwCAPI_GetNumSignals(mmi);

    xrtpi = new XrtTargetParamInfo[nBlockParams];
    xtsi = new XrtTargetSignalInfo[nSignals];

    /** Get parameter and register */      
    
    Xrt_GetParameterInfo(mmi);
    Xrt_GetSignalInfo(mmi);

    /**************** ZENOM PART  ***************/
    
    for(paramIdx = 0; paramIdx < rtwCAPI_GetNumBlockParameters(mmi); paramIdx++){
        
        std::string paramName(xrtpi[paramIdx].paramName);
        std::string blockName(xrtpi[paramIdx].blockName);

        if(paramName.empty()){
            paramName = std::string("unknownBlock");
        }
            

        for (std::size_t found = paramName.find_first_of(" "); 
            found != std::string::npos ; 
            found = paramName.find_first_of(" "))
        {
            paramName.erase (found);
        }

        for (std::size_t found = blockName.find_first_of(" "); 
            found != std::string::npos ; 
            found = blockName.find_first_of(" "))
        {
            blockName.erase (found);
        }

        paramName = blockName + "-" + paramName;
        
        registerControlVariable( xrtpi[paramIdx].dataValue, 
                                 paramName, 
                                 xrtpi[paramIdx].numRows, 
                                 xrtpi[paramIdx].numColumns );
    }

    for (sigIdx = 0; sigIdx < rtwCAPI_GetNumSignals(mmi); ++sigIdx){

        std::string sigName(xtsi[sigIdx].signalName);  

        if(sigName.empty()){
            sigName = std::string("unknownSignal");
            sigName += unknown_param_counter;
        }

        for (std::size_t found = sigName.find_first_of(" "); 
            found != std::string::npos ; 
            found = sigName.find_first_of(" "))
        {
            sigName.erase (found);
        }

        registerLogVariable(xtsi[sigIdx].dataValue,
                        sigName,
                        xtsi[sigIdx].numRows,
                        xtsi[sigIdx].numColumns);
    }

    setFrequency( (double)rtmGetStepSize(rtM) );
    setDuration ( (double)rtmGetTFinal(rtM) );

    fprintf(stderr, "init done!");
    
    return 0;
}
/**
 * \brief  Scans a mapped nandflash to find an existing logical block mapping. If a
 * block contains the mapping, its index is stored in the provided variable (if
 * pointer is not 0).
 *
 * \param mapped  Pointer to a MappedNandFlash instance.
 * \param logicalMappingBlock  Pointer to a variable for storing the block number.
 * \return  0 if mapping has been found; otherwise returns
 * NandCommon_ERROR_NOMAPPING if no mapping exists, or another NandCommon_ERROR_xxx code.
 */
static unsigned char FindLogicalMappingBlock(
    const struct MappedNandFlash *mapped,
    signed short *logicalMappingBlock)
{
    unsigned short block;
    unsigned char found;
    unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
    unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped));
    unsigned char error;
    unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned int i;

    //TRACE_INFO("FindLogicalMappingBlock ~%d\n\r", numBlocks);

    /* Search each LIVE block */
    found = 0;
    block = 0;
    while (!found && (block < numBlocks)) {

        /* Check that block is LIVE*/
        if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) {

            /* Read block*/
            TRACE_INFO("Checking LIVE block #%d\n\r", block);
            error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0);
            if (!error) {

                /* Compare data with logical mapping pattern*/
                i = 0;
                found = 1;
                while ((i < pageDataSize) && found) {

                    if (data[i] != PATTERN(i)) {

                        found = 0;
                    }
                    i++;
                }

                /* If this is the mapping, stop looking*/
                if (found) {

                    TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r",
                                     block);
                    if (logicalMappingBlock) {

                        *logicalMappingBlock = block;
                    }
                    return 0;
                }
            }
            else if (error != NandCommon_ERROR_WRONGSTATUS) {

                TRACE_ERROR(
                          "FindLogicalMappingBlock: Failed to scan block #%d\n\r",
                          block);
                return error;
            }
        }

        block++;
    }

    TRACE_WARNING("No logical mapping found in device\n\r");
    return NandCommon_ERROR_NOMAPPING;
}
/**
 * \brief  Saves the logical mapping on a FREE, unmapped physical block. Allocates the
 * new block, releases the previous one (if any) and save the mapping.
 *
 * \param mapped  Pointer to a MappedNandFlash instance.
 * \param physicalBlock  Physical block number.
 * \return  0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS
 * if the block is not LIVE, or a NandCommon_ERROR code.
 */
unsigned char MappedNandFlash_SaveLogicalMapping(
    struct MappedNandFlash *mapped,
    unsigned short physicalBlock)
{
    unsigned char error;
    unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned short pageDataSize =
                    NandFlashModel_GetPageDataSize(MODEL(mapped));
    /*unsigned short numBlocks =
                    ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));*/
    unsigned int i;
    unsigned int remainingSize;
    unsigned char *currentBuffer;
    unsigned short currentPage;
    unsigned int writeSize;
    signed short previousPhysicalBlock;

    TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\n\r", physicalBlock);

    /* If mapping has not been modified, do nothing*/
    if (!mapped->mappingModified) {

        return 0;
    }

    /* Allocate new block*/
    error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
    if (error) {

        return error;
    }

    /* Save mapping*/
    previousPhysicalBlock = mapped->logicalMappingBlock;
    mapped->logicalMappingBlock = physicalBlock;

    /* Save actual mapping in pages #1-#XXX*/
    currentBuffer = (unsigned char *) mapped->logicalMapping;
    remainingSize = sizeof(mapped->logicalMapping);
    currentPage = 1;
    while (remainingSize > 0) {

        writeSize = min(remainingSize, pageDataSize);
        memset(data, 0xFF, pageDataSize);
        memcpy(data, currentBuffer, writeSize);
        error = ManagedNandFlash_WritePage(MANAGED(mapped),
                                           physicalBlock,
                                           currentPage,
                                           data,
                                           0);
        if (error) {

            TRACE_ERROR(
             "MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r");
            return error;
        }

        currentBuffer += writeSize;
        remainingSize -= writeSize;
        currentPage++;
    }

    /* Mark page #0 of block with a distinguishible pattern, so the mapping can
       be retrieved at startup*/
    for (i=0; i < pageDataSize; i++) {

        data[i] = PATTERN(i);
    }
    error = ManagedNandFlash_WritePage(MANAGED(mapped),
                                       physicalBlock, 0,
                                       data, 0);
    if (error) {

        TRACE_ERROR(
            "MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r");
        return error;
    }

    /* Mapping is not modified anymore*/
    mapped->mappingModified = 0;

    /* Release previous block (if any)*/
    if (previousPhysicalBlock != -1) {

        TRACE_DEBUG("Previous physical block was #%d\n\r",
                    previousPhysicalBlock);
        error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped),
                                              previousPhysicalBlock);
        if (error) {

            return error;
        }
    }

    TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock);

    return 0;
}
/**
 * \brief  Loads the logical mapping contained in the given physical block.
 * block contains the mapping, its index is stored in the provided variable (if
 * pointer is not 0).
 *
 * \param mapped  Pointer to a MappedNandFlash instance.
 * \param physicalBlock  Physical block number.
 * \return  0 if successful; otherwise, returns a NandCommon_ERROR code.
 */
static unsigned char LoadLogicalMapping(
    struct MappedNandFlash *mapped,
    unsigned short physicalBlock)
{
    unsigned char error;
    unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned short pageDataSize =
                    NandFlashModel_GetPageDataSize(MODEL(mapped));
    unsigned short numBlocks =
                    ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
    unsigned int remainingSize;
    unsigned char *currentBuffer;
    unsigned short currentPage;
    unsigned int readSize;
    unsigned int i;
    unsigned char status;
    signed short logicalBlock;
    /*signed short firstBlock, lastBlock;*/

    TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock);

    /* Load mapping from pages #1 - #XXX of block*/
    currentBuffer = (unsigned char *) mapped->logicalMapping;
    remainingSize = sizeof(mapped->logicalMapping);
    currentPage = 1;
    while (remainingSize > 0) {

        /* Read page*/
        readSize = min(remainingSize, pageDataSize);
        error = ManagedNandFlash_ReadPage(MANAGED(mapped),
                                          physicalBlock,
                                          currentPage,
                                          data,
                                          0);
        if (error) {

            TRACE_ERROR(
                      "LoadLogicalMapping: Failed to load mapping\n\r");
            return error;
        }

        /* Copy page info*/
        memcpy(currentBuffer, data, readSize);

        currentBuffer += readSize;
        remainingSize -= readSize;
        currentPage++;
    }

    /* Store mapping block index*/
    mapped->logicalMappingBlock = physicalBlock;

    /* Power-loss recovery*/
    for (i=0; i < numBlocks; i++) {

        /* Check that this is not the logical mapping block*/
        if (i != physicalBlock) {

            status = mapped->managed.blockStatuses[i].status;
            logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i);

            /* Block is LIVE*/
            if (status == NandBlockStatus_LIVE) {

                /* Block is not mapped -> release it*/
                if (logicalBlock == -1) {

                    TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r",
                                     i);
                    ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i);
                }
            }
            /* Block is DIRTY*/
            else if (status == NandBlockStatus_DIRTY) {

                /* Block is mapped -> fake it as live*/
                if (logicalBlock != -1) {

                    TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r",
                                     i);
                    mapped->managed.blockStatuses[i].status =
                                                    NandBlockStatus_LIVE;
                }
            }
            /* Block is FREE or BAD*/
            else {

                /* Block is mapped -> remove it from mapping*/
                if (logicalBlock != -1) {

                    TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i);
                    mapped->logicalMapping[logicalBlock] = -1;
                }
            }
        }
    }

    TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock);

    return 0;
}