nf_mngt.c

Go to the documentation of this file.
00001 /*This file is prepared for Doxygen automatic documentation generation.*/
00016 
00017 /* Copyright (c) 2009 Atmel Corporation. All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms, with or without
00020  * modification, are permitted provided that the following conditions are met:
00021  *
00022  * 1. Redistributions of source code must retain the above copyright notice,
00023  * this list of conditions and the following disclaimer.
00024  *
00025  * 2. Redistributions in binary form must reproduce the above copyright notice,
00026  * this list of conditions and the following disclaimer in the documentation
00027  * and/or other materials provided with the distribution.
00028  *
00029  * 3. The name of Atmel may not be used to endorse or promote products derived
00030  * from this software without specific prior written permission.
00031  *
00032  * 4. This software may only be redistributed and used in connection with an Atmel
00033  * AVR product.
00034  *
00035  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
00036  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00037  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND
00038  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00039  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00040  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00041  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00042  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00043  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00044  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045  */
00046 
00047 // TODO: remplacer les s_shift_xxx en (1<<s_shift_xxx): et ainsi faire des DIV/MUL plutot que des shift
00048 // TODO: decomposer g_phys_page_addr en s_phys_block et s_phys_page (offset dans le block)
00049 
00050 //_____  I N C L U D E S ___________________________________________________
00051 
00052 #define _TRACE_        (DISABLE)
00053 #define NF_ECC_MNGT    (DISABLE)
00054 
00055 #include "config.h"
00056 #include "conf_nf.h"
00057 #include "nf.h"
00058 #include "nf_drv.h"
00059 #include "nf_mngt.h"
00060 #include "lib_mcu/usb/usb_drv.h"            /* usb driver definition */
00061 #include "lib_mcu/debug.h"
00062 
00063 
00064 #ifndef __GNUC__
00065   extern __no_init volatile xdata Byte nf_send_cmd At(NF_CMD_LATCH_ENABLE_ADD);  // Command
00066   extern __no_init volatile xdata Byte nf_send_add At(NF_ADD_LATCH_ENABLE_ADD);  // Address
00067   extern __no_init volatile xdata Byte nf_data At(NF_ADDRESS_CMD_DATA);          // Data
00068 #else
00069   extern volatile unsigned char nf_send_cmd __attribute__ ((section (".nf_cmd")));
00070   extern volatile unsigned char nf_send_add __attribute__ ((section (".nf_add")));
00071   extern volatile unsigned char nf_data     __attribute__ ((section (".nf_dat")));
00072 #endif
00073 
00074 
00075 //_____ D E F I N I T I O N ________________________________________________
00076 
00077 //#error Attention au modulo, call uidiv, uldiv, ...
00078 //Se servir plus souvent du Random Data Input pour le code 2K (création de LUT)
00079 
00080 #if( NF_BAD_CONFIG==(FALSE) )
00081 
00082 //_____ M A C R O S ________________________________________________________
00083 
00084 
00085 //_____ P R I V A T E    D E C L A R A T I O N _____________________________
00086 
00087 // Static definition, which can be optimized by the compiler
00088 //
00089 #if (NF_GENERIC_DRIVER==TRUE) || (defined NF_AUTO_DETECT_2KB) ||(defined NF_AUTO_DETECT_512B)
00090 extern _MEM_TYPE_SLOW_        U8    g_n_zones               ; // number of zones (=1024 blocks) per device
00091 extern _MEM_TYPE_SLOW_       U16  g_n_blocks              ; // number of blocks per device
00092 extern _MEM_TYPE_FAST_       U8   g_n_row_cycles          ; // number of row cycles to access a page of the NF memory
00093 extern _MEM_TYPE_SLOW_        U8    g_copy_back_cont        ; // 0 = copy back not supported, N = number of    CONTINUE subdivision contraint on copyback
00094 extern _MEM_TYPE_SLOW_        U8    g_copy_back_discont     ; // 0 = copy back not supported, N = number of DISCONTINUE subdivision contraint on copyback
00095 #endif
00096 
00097 #if (NF_GENERIC_DRIVER==TRUE)
00098        _MEM_TYPE_FAST_       U8   g_shift_page_byte       ; // (1<<n) size of page,   unit in bytes
00099        _MEM_TYPE_FAST_       U8   g_shift_block_page      ; // (1<<n) size of physical block,  unit in pages
00100        _MEM_TYPE_SLOW_       U8   g_ofst_blk_status       ; // Offset of Block Status information in spare zone
00101 static _MEM_TYPE_SLOW_       U8   s_shift_sector_byte     ; // (1<<n) size of sector, unit in bytes
00102 static _MEM_TYPE_SLOW_       U8   s_shift_log_page_sector ; // (1<<n) size of logical   page,  unit in sectors
00103 static _MEM_TYPE_SLOW_       U8   s_shift_log_block_sector; // (1<<n) size of logical  block,  unit in sectors
00104 #endif
00105 
00106 
00107        Bool g_fatal       ; // Used in LUT/FBB building and ECC management...
00108 
00109 
00110 static Bool s_mem         ;
00111 #if (defined ATMEL_WARNING)
00112 #  warning In waiting for a recoding of the control_access module.
00113 #endif
00114 static Bool s_start       ;
00115 
00116        _MEM_TYPE_SLOW_ U32  g_copy_src                         ; // Used to copy NF pages (source page)
00117        _MEM_TYPE_SLOW_ U16  g_nf_first_block=0                 ; // Block addr of the beginning of dynamic area
00118 
00119 typedef enum
00120 {
00121    STATE_READ_INIT=0       // The very first open_read must be done
00122 ,  STATE_READ_RESUME_PAGE  // A page has been read
00123 ,  STATE_WRITE_INIT        // The very first open_write must be done
00124 ,  STATE_WRITE_RESUME_PAGE // A page has been written
00125 ,  STATE_COMPLETE          // The read or write session is over.
00126 } Nf_state;
00127 
00128 
00129        _MEM_TYPE_SLOW_ Cache_lut g_cache_lut; // LUT cache
00130        _MEM_TYPE_SLOW_ Cache_fbb g_cache_fbb; // Free-Blocks block cache
00131 
00132 
00133        _MEM_TYPE_SLOW_ U8   g_page_buffer[NF_FULL_PAGE_BUFFER_SIZE] ; // Used to bufferize a page
00134 
00135 // Dynamic variables
00136 //
00137 static _MEM_TYPE_SLOW_    U32       s_save_log_addr              ; // Used for Stand-by / Restart operations
00138 //static _MEM_TYPE_SLOW_    U16       s_save_n_sector              ; // Used for Stand-by / Restart operations
00139 //static _MEM_TYPE_SLOW_    U32       s_save2_log_addr             ; // Used for Stand-by / Restart operations
00140 //static _MEM_TYPE_SLOW_    U16       s_save2_n_sector             ; // Used for Stand-by / Restart operations
00141        _MEM_TYPE_BIT_     bit       g_nf_init                    ; // Boolean set when driver is initialized
00142        _MEM_TYPE_MEDFAST_ U16       g_log_block_id               ; // Logical Block address
00143        _MEM_TYPE_SLOW_    U16       g_n_export_blocks=0xFFFF     ; // Number of physical blocks exported for mass-storage use
00144        _MEM_TYPE_SLOW_    U16       g_n_free_blocks              ; // Number of free physical blocks
00145        _MEM_TYPE_SLOW_    U8        g_n_sub_lut                  ; // Holds the number of sub-Lut
00146        _MEM_TYPE_SLOW_    U16       g_sub_lut_log_sz             ; // Size of the sub-LUT. Unit in number of logical blocks
00147        _MEM_TYPE_SLOW_    U16       g_last_sub_lut_log_sz        ; // Size of the last sub-LUT. Unit in number of logical blocks
00148        _MEM_TYPE_SLOW_    U16       g_fbb_block_addr             ; // Free-Blocks block address
00149        _MEM_TYPE_SLOW_    U8        g_fbb_block_index            ; // Free-Blocks block index
00150        _MEM_TYPE_SLOW_    U16       g_lut_block_addr [ N_SUBLUT ]; // LUT block address
00151        _MEM_TYPE_SLOW_    U8        g_lut_block_index[ N_SUBLUT ]; // LUT index, unit in (LUT size/page size)
00152 
00153 static _MEM_TYPE_FAST_    U16       s_n_sectors                  ; // Holds the number of sectors to read/write
00154 static _MEM_TYPE_FAST_    U8        s_nb_sectors_step            ; // Holds the number of sectors read after each page
00155        _MEM_TYPE_FAST_    U8        g_curr_dev_id                ; // Holds the current device number that is used
00156 static _MEM_TYPE_FAST_    U16       s_curr_n_byte                ; // Holds the position in the page
00157 static _MEM_TYPE_FAST_    U32       s_curr_log_sector            ; // Holds the logical sector number
00158        _MEM_TYPE_SLOW_    U32       g_last_log_sector =0xFFFFFFFF; // Holds the last logical sector number on which a Write has been done
00159 static _MEM_TYPE_FAST_    Nf_state  s_state                      ; // Holds the current state of the driver
00160 
00161        _MEM_TYPE_SLOW_    U16       g_block_to_kill[ NF_N_DEVICES]    ; // Holds the blocks number which will be erased
00162        _MEM_TYPE_FAST_    U32       g_phys_page_addr[NF_N_DEVICES]    ; // Holds the current phys page number for each device
00163 
00164        _MEM_TYPE_SLOW_    U32       g_save_phys_page_addr             ; // Holds the previous phys page number
00165        _MEM_TYPE_SLOW_    U8        g_save_curr_dev_id                ; // Holds the previous device number that is used
00166 
00167        _MEM_TYPE_FAST_    U32       g_next_phys_page_addr             ; // Holds the previous phys page number
00168 
00169 typedef enum
00170 {
00171    NF_TRANS_NORMAL  // make simple translation.
00172 ,  NF_TRANS_FLUSH   // make simple translation. Force flush of LUT and FBB caches.
00173 ,  NF_TRANS_SWAP    // Swap blocks LUT <-> FBB
00174 } Nf_translate_mode;
00175 
00176 
00177 //_____ P R I V A T E    F U N C T I O N S _________________________________
00178 //
00179 static void        nf_translate( Nf_translate_mode mode );
00180 static Status_bool nf_open_read(    bit check_pending_write );
00181 static Status_bool nf_open_write(   bit check_pending_write );
00182 static void        nf_cache_lut_refill( U16 log_block_id  );
00183 static void        nf_cache_lut_flush( void  );
00184 static void        nf_erase_old_blocks( void );
00185 
00186 U8                 nf_xfer_update_vars(void);
00187 void               nf_write_sector_from_usb(U8);
00188 void               nf_read_sector_to_usb(U8);
00189 void               nf_update_spare_zone(U8, U8);
00190 
00191 //_____ F U N C T I O N S __________________________________________________
00192 //
00193 
00202 Status_bool nf_verify( void )
00203 {
00204    if ( g_nf_init ) return PASS;
00205 
00206    return nf_verify_resume();
00207 }
00208 
00209 
00210 
00218 Ctrl_status nf_test_unit_ready ( void )
00219 {
00220   Status_bool tmp_bool;
00221 
00222 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00223    nf_XMCR_enable();
00224 #endif
00225 
00226    tmp_bool = nf_verify();
00227 
00228 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00229    nf_XMCR_disable();
00230 #endif
00231 
00232    return ( tmp_bool==PASS ) ? CTRL_GOOD : CTRL_FAIL;
00233 }
00234 
00235 
00243 Ctrl_status nf_read_capacity (U32  *u32_nb_sector )
00244 {
00245   Status_bool status_bool;
00246 
00247 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00248    nf_XMCR_enable();
00249 #endif
00250 
00251    status_bool = nf_verify();
00252 
00253 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00254    nf_XMCR_disable();
00255 #endif
00256 
00257    *u32_nb_sector = nf_get_sectors_number()-1;
00258    return ( status_bool==PASS ) ? CTRL_GOOD : CTRL_FAIL;
00259 }
00260 
00261 
00262 Bool  nf_wr_protect ( void )
00263 {
00264     return FALSE;
00265 }
00266 
00267 Bool  nf_removal ( void )
00268 {
00269     return TRUE;
00270 }
00271 
00272 
00281 #if 0
00282 U8*  nf_get_buffer_addr         ( void ) { return g_page_buffer; }
00283 #endif
00284 
00285 
00296 U32  nf_get_sectors_number      ( void )
00297 {
00298    return
00299       (U32)g_n_export_blocks
00300    << (G_SHIFT_BLOCK_PAGE +G_SHIFT_PAGE_BYTE -S_SHIFT_SECTOR_BYTE)
00301    ;
00302 }
00303 
00304 
00305 
00306 U32 nf_block_2_page(U16 block_addr)
00307 {
00308    return (U32)block_addr<<G_SHIFT_BLOCK_PAGE;
00309 }
00310 
00311 
00312 
00320 Ctrl_status nf_read_10( U32 log_sector , U16 n_sectors)
00321 {
00322   U8  status;
00323   
00324    if ( !g_nf_init )
00325       while(1);   // You shall call once mem_test_unit_ready() before.
00326 
00327    // Test that the logical sector address is valid
00328    //
00329    if ( 0==n_sectors )                                   { return CTRL_GOOD; }
00330    if ( (log_sector+n_sectors)>nf_get_sectors_number() ) { return CTRL_FAIL; }
00331 
00332 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00333    nf_XMCR_enable();
00334 #endif
00335 
00336    s_n_sectors       = n_sectors;
00337    s_curr_log_sector = log_sector;
00338    trace("rd;"); trace_hex32(s_curr_log_sector); trace(";"); trace_hex16(s_n_sectors); trace_nl();
00339    s_save_log_addr   = log_sector + n_sectors;
00340    g_fatal           = FALSE;
00341    s_mem             = TRUE;
00342    s_start           = TRUE;
00343 
00344    // First read operation
00345    Nf_access_signal_on();
00346    nf_open_read(TRUE);
00347    Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);
00348    nfc_open_page_read( g_phys_page_addr[g_curr_dev_id], s_curr_n_byte );
00349    nf_read_sector_to_usb(s_nb_sectors_step);
00350    status = nf_xfer_update_vars();
00351 
00352    // Next read operations
00353    while (status == FALSE)    // exit when last page read
00354    {
00355       if (!(LSB0(g_next_phys_page_addr) & (SIZE_BLOCK_PAGE-1))    // new block
00356       && (g_curr_dev_id==0                                  ))    // on device 0. Should this case be implicit ? If yes, we can remove it.
00357       {
00358          nf_open_read(FALSE);
00359       }
00360       Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);
00361       Nfc_open_page_read( g_next_phys_page_addr, s_curr_n_byte ); // Use macro for fast execution
00362       nf_read_sector_to_usb(s_nb_sectors_step);                   // read the concerned sectors of the selected page
00363       status = nf_xfer_update_vars();                             // check if last page or not
00364    }
00365 
00366    Nf_access_signal_off();
00367 
00368 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00369    nf_XMCR_disable();
00370 #endif
00371 
00372    return CTRL_GOOD;
00373 }
00374 
00375 
00376 
00384 Ctrl_status nf_write_10( U32 log_sector , U16 n_sectors)
00385 {
00386   U8 status;
00387   Ctrl_status tmp_bool;
00388 
00389    // Test that the logical sector address is valid
00390    if ( 0==n_sectors )                                   { return CTRL_GOOD; }
00391    if ( (log_sector+n_sectors)>nf_get_sectors_number() ) { return CTRL_FAIL; }
00392 
00393 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00394    nf_XMCR_enable();
00395 #endif
00396 
00397    s_n_sectors       = n_sectors;
00398    s_curr_log_sector = log_sector;
00399    s_save_log_addr   = log_sector + n_sectors;
00400    g_fatal           = FALSE;
00401    s_mem             = TRUE;
00402    s_start           = TRUE;
00403 
00404    trace("wr;"); trace_hex32(s_curr_log_sector); trace(";"); trace_hex16(s_n_sectors); trace_nl();
00405    
00406    // First write operation
00407    Nf_access_signal_on();
00408    if(( s_curr_log_sector==g_last_log_sector )                                           // New write is just after to the last write
00409    && (!(  ( 0==((U16)g_last_log_sector & ( ((U16)1<<(S_SHIFT_LOG_BLOCK_SECTOR)) -1)))   // Not on a logical block boundary
00410       && ( g_curr_dev_id==0                                                        ))))
00411    {
00412       trace("continue");trace_nl();
00413       nf_translate( NF_TRANS_NORMAL );
00414       Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);  // open the current device
00415       nfc_open_page_write( g_next_phys_page_addr, s_curr_n_byte );
00416    }
00417    else
00418    {      
00419       nf_open_write( TRUE );
00420    }
00421    nf_write_sector_from_usb(s_nb_sectors_step);    // s_nb_sectors_step has been calculated in nf_translate()
00422    if (Is_nf_2k())
00423    {
00424       nf_update_spare_zone((U8)(1<<(G_SHIFT_PAGE_BYTE - S_SHIFT_SECTOR_BYTE))-s_nb_sectors_step, s_nb_sectors_step);    // update the spare zone once the page has been filled in
00425    }
00426    else
00427    {
00428      nf_update_spare_zone(0, 1);    // update the spare zone once the page has been filled in
00429    }
00430    g_last_log_sector  = s_curr_log_sector + s_nb_sectors_step;    // Memorize next logical sector to be managed
00431    status = nf_xfer_update_vars();
00432 
00433    // Next write operations
00434    while (status == FALSE)    // exit when operation finished
00435    {
00436       if(!(LSB0(g_next_phys_page_addr) & (SIZE_BLOCK_PAGE-1))  // new block
00437       && (g_curr_dev_id==0                                  )) // on device 0.
00438       {
00439          Nfc_set_cmd(NF_PAGE_PROGRAM_CMD); // Program the page
00440          nf_erase_old_blocks();
00441          nf_open_write( FALSE );
00442       }
00443       else
00444       {
00445          if( G_CACHE_PROG )
00446          {
00447             Nfc_set_cmd(NF_CACHE_PROGRAM_CMD);
00448          }else{
00449             Nfc_set_cmd(NF_PAGE_PROGRAM_CMD);
00450          }
00451          Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);
00452          Nfc_open_page_write( g_next_phys_page_addr, s_curr_n_byte ); // Use macro for fast execution
00453       }
00454       nf_write_sector_from_usb(s_nb_sectors_step);
00455       if (Is_nf_2k())
00456       {
00457          nf_update_spare_zone(0, s_nb_sectors_step);
00458       }
00459       else
00460       {
00461          nf_update_spare_zone(0, 1);    // update the spare zone once the page has been filled in
00462       }
00463       g_last_log_sector  = s_curr_log_sector + s_nb_sectors_step;    // Memorize next logical sector to be managed
00464       status = nf_xfer_update_vars();  // check if last block or not
00465    }
00466 
00467    tmp_bool = nf_dfc_write_stop(0);   // ends write operations with "nf_dfc_write_stop(0)" that save the current environnement
00468    Nf_access_signal_off();
00469 
00470 #if (NF_XMCR_MODULE_SHARED == ENABLED)
00471    nf_XMCR_disable();
00472 #endif
00473 
00474    return tmp_bool;
00475 }
00476 
00477 
00478 
00479 
00480 //_____ P R I V A T E    F U N C T I O N S _________________________________
00481 //
00482 
00490 U8 nf_xfer_update_vars(void)
00491 {
00492    if ( // Are we processing the last page ?
00493       (  (s_curr_log_sector & (SIZE_PAGE_SECTOR-1))
00494       +  s_n_sectors
00495       )
00496    <  SIZE_PAGE_SECTOR
00497    ) {
00498       s_state = STATE_COMPLETE;
00499       return TRUE;
00500    }
00501 
00502    // Update position variables
00503    s_n_sectors       -= s_nb_sectors_step;
00504    s_curr_log_sector += s_nb_sectors_step;
00505    s_curr_n_byte = 0;
00506    if (s_n_sectors < SIZE_PAGE_SECTOR)
00507      s_nb_sectors_step = (U8) (s_n_sectors);   // next page must be read as partial (not all sectors remaining)
00508    else
00509      s_nb_sectors_step = SIZE_PAGE_SECTOR;     // next page to be read considered as entire (all sectors requested)
00510 
00511    // Save current parameters
00512    g_save_curr_dev_id    = g_curr_dev_id;
00513    g_save_phys_page_addr = g_phys_page_addr[g_curr_dev_id];
00514 
00515    // Fetch the next device id
00516    //
00517    g_phys_page_addr[g_curr_dev_id]+=1;
00518    g_curr_dev_id ++;
00519    if( g_curr_dev_id==NF_N_DEVICES ) { g_curr_dev_id=0; }
00520 
00521    g_next_phys_page_addr = g_phys_page_addr[g_curr_dev_id];
00522 
00523    if( s_n_sectors==0 )    // Operation complete !
00524    {
00525      s_state = STATE_COMPLETE;
00526      return TRUE;
00527    }
00528 
00529    return FALSE;
00530 }
00531 
00532 
00540 void nf_read_sector_to_usb(U8 nb_sectors)
00541 {
00542  U8 j;
00543 
00544    for (j = 8*nb_sectors; j != 0; j--)                      // 8 * 64 bytes = 512 bytes
00545    {
00546       Disable_interrupt();
00547 
00548       Usb_write_byte(Nf_rd_byte());                         // read 64 bytes from card
00549       Usb_write_byte(Nf_rd_byte());
00550       Usb_write_byte(Nf_rd_byte());
00551       Usb_write_byte(Nf_rd_byte());
00552       Usb_write_byte(Nf_rd_byte());
00553       Usb_write_byte(Nf_rd_byte());
00554       Usb_write_byte(Nf_rd_byte());
00555       Usb_write_byte(Nf_rd_byte());
00556       Usb_write_byte(Nf_rd_byte());
00557       Usb_write_byte(Nf_rd_byte());
00558       Usb_write_byte(Nf_rd_byte());
00559       Usb_write_byte(Nf_rd_byte());
00560       Usb_write_byte(Nf_rd_byte());
00561       Usb_write_byte(Nf_rd_byte());
00562       Usb_write_byte(Nf_rd_byte());
00563       Usb_write_byte(Nf_rd_byte());
00564       Usb_write_byte(Nf_rd_byte());
00565       Usb_write_byte(Nf_rd_byte());
00566       Usb_write_byte(Nf_rd_byte());
00567       Usb_write_byte(Nf_rd_byte());
00568       Usb_write_byte(Nf_rd_byte());
00569       Usb_write_byte(Nf_rd_byte());
00570       Usb_write_byte(Nf_rd_byte());
00571       Usb_write_byte(Nf_rd_byte());
00572       Usb_write_byte(Nf_rd_byte());
00573       Usb_write_byte(Nf_rd_byte());
00574       Usb_write_byte(Nf_rd_byte());
00575       Usb_write_byte(Nf_rd_byte());
00576       Usb_write_byte(Nf_rd_byte());
00577       Usb_write_byte(Nf_rd_byte());
00578       Usb_write_byte(Nf_rd_byte());
00579       Usb_write_byte(Nf_rd_byte());
00580       Usb_write_byte(Nf_rd_byte());
00581       Usb_write_byte(Nf_rd_byte());
00582       Usb_write_byte(Nf_rd_byte());
00583       Usb_write_byte(Nf_rd_byte());
00584       Usb_write_byte(Nf_rd_byte());
00585       Usb_write_byte(Nf_rd_byte());
00586       Usb_write_byte(Nf_rd_byte());
00587       Usb_write_byte(Nf_rd_byte());
00588       Usb_write_byte(Nf_rd_byte());
00589       Usb_write_byte(Nf_rd_byte());
00590       Usb_write_byte(Nf_rd_byte());
00591       Usb_write_byte(Nf_rd_byte());
00592       Usb_write_byte(Nf_rd_byte());
00593       Usb_write_byte(Nf_rd_byte());
00594       Usb_write_byte(Nf_rd_byte());
00595       Usb_write_byte(Nf_rd_byte());
00596       Usb_write_byte(Nf_rd_byte());
00597       Usb_write_byte(Nf_rd_byte());
00598       Usb_write_byte(Nf_rd_byte());
00599       Usb_write_byte(Nf_rd_byte());
00600       Usb_write_byte(Nf_rd_byte());
00601       Usb_write_byte(Nf_rd_byte());
00602       Usb_write_byte(Nf_rd_byte());
00603       Usb_write_byte(Nf_rd_byte());
00604       Usb_write_byte(Nf_rd_byte());
00605       Usb_write_byte(Nf_rd_byte());
00606       Usb_write_byte(Nf_rd_byte());
00607       Usb_write_byte(Nf_rd_byte());
00608       Usb_write_byte(Nf_rd_byte());
00609       Usb_write_byte(Nf_rd_byte());
00610       Usb_write_byte(Nf_rd_byte());
00611       Usb_write_byte(Nf_rd_byte());
00612       Enable_interrupt();
00613 
00614       Usb_send_in();                            // validate transfer
00615       while(Is_usb_write_enabled()==FALSE)
00616       {
00617          if(!Is_usb_endpoint_enabled())
00618             return; // USB Reset
00619       }
00620    }
00621 }
00622 
00623 
00624 
00632 void nf_write_sector_from_usb(U8 nb_sectors)
00633 {
00634    U8 j;
00635    for (j = 8*nb_sectors ; j != 0 ; j--)        // 8 * 64 bytes = 512 bytes
00636    {
00637       while(!Is_usb_read_enabled())
00638       {
00639          if(!Is_usb_endpoint_enabled())
00640            return; // USB Reset
00641       }
00642       Disable_interrupt();                      // Global disable.
00643 
00644       Nf_wr_byte(Usb_read_byte());              // write 64 bytes to the card
00645       Nf_wr_byte(Usb_read_byte());
00646       Nf_wr_byte(Usb_read_byte());
00647       Nf_wr_byte(Usb_read_byte());
00648       Nf_wr_byte(Usb_read_byte());
00649       Nf_wr_byte(Usb_read_byte());
00650       Nf_wr_byte(Usb_read_byte());
00651       Nf_wr_byte(Usb_read_byte());
00652       Nf_wr_byte(Usb_read_byte());
00653       Nf_wr_byte(Usb_read_byte());
00654       Nf_wr_byte(Usb_read_byte());
00655       Nf_wr_byte(Usb_read_byte());
00656       Nf_wr_byte(Usb_read_byte());
00657       Nf_wr_byte(Usb_read_byte());
00658       Nf_wr_byte(Usb_read_byte());
00659       Nf_wr_byte(Usb_read_byte());
00660       Nf_wr_byte(Usb_read_byte());
00661       Nf_wr_byte(Usb_read_byte());
00662       Nf_wr_byte(Usb_read_byte());
00663       Nf_wr_byte(Usb_read_byte());
00664       Nf_wr_byte(Usb_read_byte());
00665       Nf_wr_byte(Usb_read_byte());
00666       Nf_wr_byte(Usb_read_byte());
00667       Nf_wr_byte(Usb_read_byte());
00668       Nf_wr_byte(Usb_read_byte());
00669       Nf_wr_byte(Usb_read_byte());
00670       Nf_wr_byte(Usb_read_byte());
00671       Nf_wr_byte(Usb_read_byte());
00672       Nf_wr_byte(Usb_read_byte());
00673       Nf_wr_byte(Usb_read_byte());
00674       Nf_wr_byte(Usb_read_byte());
00675       Nf_wr_byte(Usb_read_byte());
00676       Nf_wr_byte(Usb_read_byte());
00677       Nf_wr_byte(Usb_read_byte());
00678       Nf_wr_byte(Usb_read_byte());
00679       Nf_wr_byte(Usb_read_byte());
00680       Nf_wr_byte(Usb_read_byte());
00681       Nf_wr_byte(Usb_read_byte());
00682       Nf_wr_byte(Usb_read_byte());
00683       Nf_wr_byte(Usb_read_byte());
00684       Nf_wr_byte(Usb_read_byte());
00685       Nf_wr_byte(Usb_read_byte());
00686       Nf_wr_byte(Usb_read_byte());
00687       Nf_wr_byte(Usb_read_byte());
00688       Nf_wr_byte(Usb_read_byte());
00689       Nf_wr_byte(Usb_read_byte());
00690       Nf_wr_byte(Usb_read_byte());
00691       Nf_wr_byte(Usb_read_byte());
00692       Nf_wr_byte(Usb_read_byte());
00693       Nf_wr_byte(Usb_read_byte());
00694       Nf_wr_byte(Usb_read_byte());
00695       Nf_wr_byte(Usb_read_byte());
00696       Nf_wr_byte(Usb_read_byte());
00697       Nf_wr_byte(Usb_read_byte());
00698       Nf_wr_byte(Usb_read_byte());
00699       Nf_wr_byte(Usb_read_byte());
00700       Nf_wr_byte(Usb_read_byte());
00701       Nf_wr_byte(Usb_read_byte());
00702       Nf_wr_byte(Usb_read_byte());
00703       Nf_wr_byte(Usb_read_byte());
00704       Nf_wr_byte(Usb_read_byte());
00705       Nf_wr_byte(Usb_read_byte());
00706       Nf_wr_byte(Usb_read_byte());
00707       Nf_wr_byte(Usb_read_byte());
00708 
00709       Usb_ack_receive_out();           // USB EPOUT read acknowledgement.
00710       Enable_interrupt();              // Global re-enable.
00711    }
00712 }
00713 
00714 
00724 void nf_update_spare_zone(U8 sect_start, U8 nb_sect)
00725 {
00726    // Calculate first spare zone address
00727    U8 i;
00728    _MEM_TYPE_SLOW_ U16 byte_addr = NF_SPARE_POS + ((U16)sect_start)*16;
00729 
00730   // Send command + address if 2kb' page model
00731    if (Is_nf_2k())
00732    {
00733       Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
00734       Nfc_set_adc( (byte_addr)%256 );
00735       Nfc_set_adc( (byte_addr)/256 );
00736    }
00737 
00738    // Send data (spare zone x sectors written)
00739    for( i=nb_sect ; i!=0 ; i-- )
00740    {
00741       Nfc_wr_data( 0xFF                 ); // 0- [FW] block is valid (for 2048 compatibility)
00742       Nfc_wr_data( NFC_BLK_ID_DATA      ); // 1- [FW] Free-blocks block
00743       Nfc_wr_data( 0                    ); // 2- [HW] ECC is valid
00744       Nfc_wr_data( NFC_OFST_3_DATA_DST  ); // 3- [SW] Source block (recovery) (HW capability not used)
00745       Nfc_wr_data( NFC_SPARE_DATA_VALID ); // 4- [FW] Data is valid
00746       Nfc_wr_data( 0xFF                 ); // 5- [FW] block is valid (for 512 compatibility)
00747       Nfc_wr_data( MSB(g_log_block_id)  ); // 6- [HW] LBA
00748       Nfc_wr_data( LSB(g_log_block_id)  ); // 7- [HW] LBA
00749       Nfc_wr_data( 0xFF                 ); // 8-9-10- [HW] ECC2
00750       Nfc_wr_data( 0xFF                 );
00751       Nfc_wr_data( 0xFF                 );
00752       Nfc_wr_data( 0xFF                 ); // 11-12-    [HW] LBA
00753       Nfc_wr_data( 0xFF                 );
00754       Nfc_wr_data( 0xFF                 );
00755       Nfc_wr_data( 0xFF                 );
00756       Nfc_wr_data( 0xFF                 ); // 13-14-15- [HW] ECC1
00757    }
00758 }
00759 
00760 
00761 
00770 Ctrl_status nf_dfc_write_stop( U16 u16_nb_sector_remaining ) // function that stops the dfc interface of the memory
00771 {
00772    Nfc_set_cmd(NF_PAGE_PROGRAM_CMD); // Program the page
00773    // Note that if the page is not completely filled in yet but still programmed, the next copy tail will allow partial page program
00774 
00775    // retreive exact logical/physical position (in case that transfer
00776    // did not perform the exact number of sectors)
00777    s_curr_log_sector = s_save_log_addr - u16_nb_sector_remaining;
00778    if( 0!=u16_nb_sector_remaining )
00779    {
00780       nf_translate( NF_TRANS_NORMAL );
00781    }
00782    g_last_log_sector  = s_curr_log_sector; // Memorize next logical sector to be managed
00783 
00784    // Test if transfer stop at end of logical blocks.
00785    if( s_n_sectors==0 )
00786    {
00787       if(!(LSB0(g_next_phys_page_addr) & (SIZE_BLOCK_PAGE-1))  // new block
00788       && (g_curr_dev_id==0                                  )) // on device 0.
00789      {
00790          // Delete old blocks
00791          //
00792          nf_erase_old_blocks();
00793       }
00794    }
00795    trace("nf_dfc_write_stop;"); trace_hex32(g_last_log_sector); trace_nl();
00796 
00797    // Ensure that all internal programming are complete, since we are
00798    // using cache programming (WP may be asserted for icons or fonts
00799    // loading). Moreover, on some NFs (ST, Samsung)
00800    // it is necessary to reset the devices after copy-back commands
00801    // If not, strange behaviour may happen: no busy when opening
00802    // a page for reading...
00803    nfc_reset_nands( NF_N_DEVICES ); // Reset all the NF devices
00804 
00805    Nf_check_fbb( FALSE );
00806    Nf_check_lut();
00807 
00808    return CTRL_GOOD;
00809 } // end of nf_dfc_write_stop
00810 
00811 
00812 
00819 static void nf_erase_old_blocks( void )
00820 {
00821    U8  i;
00822 
00823    // Delete old blocks
00824    //
00825    for ( i=0 ; i<NF_N_DEVICES ; i++ )
00826    {
00827       Nfc_action(NFC_ACT_DEV_SELECT, i);
00828       trace("nf_erase_old_blocks;"); trace_hex16(g_block_to_kill[i]);trace_nl();
00829       nfc_erase_block( nf_block_2_page(g_block_to_kill[i]), TRUE );
00830    }
00831 }
00832 
00833 
00834 
00845 //#error finaliser l'activation du CE[dev]
00846 //#error attention a l'horloge CLK read et CLK write
00847 static Status_bool nf_open_read( bit check_pending_write )
00848 {
00849    if(( check_pending_write   )
00850    && ( 0xFFFFFFFF!=g_last_log_sector ))
00851    {
00852       nf_copy_tail();
00853    }
00854 
00855    // Both LUT and FBB caches are flushed. Why?
00856    // - Avoid LUT/FBB caches flush and refill during audio playback
00857    // - Avoid recovery on power-on
00858    nf_translate( NF_TRANS_FLUSH );
00859 
00860    return PASS;
00861 }
00862 
00863 
00880 static Status_bool nf_open_write( bit check_pending_write )
00881 {
00882    U8  u8_tmp;
00883    _MEM_TYPE_SLOW_ U8  u8_curr_page;
00884    _MEM_TYPE_SLOW_ U8  u8_last_page;
00885    U16 u16_tmp;
00886 
00887    if(( check_pending_write   )
00888    && ( 0xFFFFFFFF!=g_last_log_sector ))
00889    {
00890       nf_copy_tail();
00891    }
00892 
00893    nf_translate( NF_TRANS_SWAP );
00894 
00895    // both FBB and LUT blocks are invalid
00896    // Mark FBB only. Warning: Partial Prog
00897    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
00898    nfc_open_page_write(
00899       nf_block_2_page( g_fbb_block_addr )  // base address
00900    +  (U32)g_fbb_block_index               // offset to Free-blocks block entry
00901    ,  NF_SPARE_POS+NFC_SPARE_OFST_6_LBA );
00902    Nfc_wr_data( NFC_OFST_6_FBB_INVALID );                         // 6- FBB-LUTs are invalid
00903    Nfc_set_cmd( NF_PAGE_PROGRAM_CMD );                            // Warning: Partial Programming
00904 
00905    // Mark sources blocks (recovery). Warning: Partial Prog
00906    for( u8_tmp=0 ; u8_tmp<NF_N_DEVICES ; u8_tmp++ )
00907    {
00908       Nfc_action(NFC_ACT_DEV_SELECT, u8_tmp);
00909       nfc_open_page_write(
00910          nf_block_2_page( g_block_to_kill[u8_tmp] )
00911       ,  NF_SPARE_POS+NFC_SPARE_OFST_3_BYTE_3 );
00912       Nfc_wr_data( NFC_OFST_3_DATA_SRC );                         // 3- [SW] Mark as source block (recovery) (HW capability not used)
00913       Nfc_set_cmd( NF_PAGE_PROGRAM_CMD );                         // Warning: Partial Programming
00914    }
00915 
00916    // Copy the head of the buffer
00917    //
00918    // for each logical page (current included)
00919    u8_last_page= (s_curr_log_sector >>S_SHIFT_LOG_PAGE_SECTOR) & (SIZE_BLOCK_PAGE -1);
00920    for(  u8_curr_page=0
00921    ;     u8_curr_page <= u8_last_page
00922    ;     u8_curr_page++ )
00923    {
00924       // If the last page (current)
00925       if ( u8_last_page==u8_curr_page ) { u8_tmp = g_curr_dev_id; } // then copy this physical page only for the device before the current device
00926       else                              { u8_tmp = NF_N_DEVICES;  } // else copy this physical page for all device
00927 
00928       while( u8_tmp!=0 ) // for each device
00929       {
00930          u8_tmp--;
00931          Nfc_action(NFC_ACT_DEV_SELECT, u8_tmp);
00932 
00933          g_copy_src= nf_block_2_page( g_block_to_kill[u8_tmp] ) + u8_curr_page;
00934          nf_copy(g_phys_page_addr[u8_tmp]);
00935          g_phys_page_addr[u8_tmp]++;
00936       }
00937       // end of loop, for each device
00938    }
00939    // end of loop, for each logical page
00940 
00941    u16_tmp=
00942       (SIZE_SECTOR_BYTE)                          // size (unit byte) of the sector (spare zone excluded)
00943    *  (  s_curr_log_sector                        // current sector in physical page
00944       &  (SIZE_PAGE_SECTOR -1)
00945       );
00946 
00947    Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);
00948    if( u16_tmp )
00949    {
00950       //** copy the head of the current physical page
00951       nfc_open_page_read( nf_block_2_page( g_block_to_kill[g_curr_dev_id] ) + u8_last_page, 0 );
00952       // copy the head page of the old block in buffer
00953       nf_upload(g_page_buffer, (U8)(u16_tmp/16));
00954    }
00955 
00956    // copy the buffer in the head page of the new block
00957    nfc_open_page_write( g_phys_page_addr[g_curr_dev_id], 0 );
00958 
00959    // write the first byte to the current byte position in the physical page
00960    nf_download(g_page_buffer, (U8)(u16_tmp/16));
00961    // END of the copy head
00962 
00963    return PASS;
00964 } // nf_open_write
00965 
00966 
00967 
00980 static void nf_cache_lut_refill(U16 log_block_id)
00981 {
00982    U8  u8_tmp;
00983    U8  sub_lut_id;
00984 
00985    U16 byte_addr;
00986    _MEM_TYPE_SLOW_ U32 page_addr;
00987    _MEM_TYPE_SLOW_ U16 sub_lut_log_sz;    // size of the sub-LUT. Unit in logical blocks.
00988    _MEM_TYPE_SLOW_ U16 sub_lut_log_first; // number of the first logical block of the sub-lut.
00989 
00990    Assert( g_cache_lut.ctrl.dirty==FALSE ); // No refill if the cache is dirty
00991 
00992    sub_lut_id        = log_block_id>>(    NF_SHIFT_SUBLUT_PHYS - NF_SHIFT_N_DEVICES);
00993    sub_lut_log_sz    = ( sub_lut_id==(g_n_sub_lut-1) ? g_last_sub_lut_log_sz : g_sub_lut_log_sz );
00994    sub_lut_log_first = (U16)sub_lut_id<<( NF_SHIFT_SUBLUT_PHYS - NF_SHIFT_N_DEVICES);
00995 
00996    trace("nf_cache_lut_refill;"); trace_hex16(g_lut_block_addr[sub_lut_id]);trace_nl();
00997 
00998    if (sub_lut_log_sz<NF_CACHE_LUT_LOG_SZ)
00999    {  // The cache is bigger than the sub LUT
01000       g_cache_lut.first = log_block_id;                               // First included
01001       g_cache_lut.last  = log_block_id + (sub_lut_log_sz-1);          // Last included
01002    }
01003    else if ( (log_block_id+NF_CACHE_LUT_LOG_SZ) <= (sub_lut_log_first+sub_lut_log_sz) )
01004    {  // The cache is done starting from the logical block number
01005       g_cache_lut.first = log_block_id;                               // First included
01006       g_cache_lut.last  = log_block_id + (NF_CACHE_LUT_LOG_SZ-1);     // Last included
01007    }
01008    else
01009    {  // The cache is done starting from the last logical block of the sub-LUT
01010       g_cache_lut.last  = sub_lut_log_first +sub_lut_log_sz -1;       // Last included
01011       g_cache_lut.first = g_cache_lut.last - (NF_CACHE_LUT_LOG_SZ-1); // First included
01012    }
01013 
01014    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01015 
01016    page_addr =
01017       nf_block_2_page( g_lut_block_addr[sub_lut_id]) // base address
01018    +  (U32)(g_lut_block_index[sub_lut_id])           // offset to sub-LUT
01019    ;
01020    byte_addr = ( (g_cache_lut.first-sub_lut_log_first)*NF_N_DEVICES*2 ); // logical position of the block
01021    Assert( byte_addr<SIZE_PAGE_BYTE );
01022 
01023    nfc_open_page_read( page_addr, byte_addr);
01024    trace_hex32(page_addr); trace(";"); trace_hex16(byte_addr);trace_nl();
01025    for ( u8_tmp=0 ; u8_tmp<(g_cache_lut.last+1-g_cache_lut.first)*NF_N_DEVICES ; u8_tmp++ )
01026    { // fill the cache buffer
01027       Assert( u8_tmp<CACHE_LUT_SIZE);
01028       MSB(g_cache_lut.mem[u8_tmp]) = Nfc_rd_data_fetch_next();
01029       LSB(g_cache_lut.mem[u8_tmp]) = Nfc_rd_data_fetch_next();
01030       trace_hex16(g_cache_lut.mem[u8_tmp]);
01031       trace("-");
01032       Assert( g_cache_lut.mem[u8_tmp]>=g_nf_first_block );
01033       Assert( g_cache_lut.mem[u8_tmp]< G_N_BLOCKS       );
01034    }
01035    trace_nl();
01036    g_cache_lut.ctrl.valid = TRUE;
01037 } // end of nf_cache_lut_refill
01038 
01039 
01040 
01049 void nf_cache_fbb_refill(void)
01050 {
01051    U8  u8_tmp;
01052    U16 byte_addr;
01053    _MEM_TYPE_SLOW_ U32 page_addr;
01054 
01055    Assert(g_cache_fbb.ctrl.dirty==FALSE); // No refill if the cache is dirty
01056    g_cache_fbb.p   = 0;
01057 
01058    trace("nf_cache_fbb_refill;"); trace_hex16(g_fbb_block_addr);trace_nl();
01059 
01060    // Ensure that the cache is bigger than the real number of free blocks
01061    //
01062    g_cache_fbb.max = Min(NF_CACHE_FBB_LOG_SZ, (g_n_free_blocks>>NF_SHIFT_N_DEVICES) ); // Last included
01063 
01064    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01065 
01066    page_addr =
01067       nf_block_2_page( g_fbb_block_addr  ) // base address
01068    +  (U32)g_fbb_block_index               // offset to Free-blocks block entry
01069    ;
01070    byte_addr=0;
01071 
01072    nfc_open_page_read(page_addr, 0);
01073 
01074    for ( u8_tmp=0 ; u8_tmp<g_cache_fbb.max*NF_N_DEVICES ; u8_tmp++ )
01075    { // fill the cache buffer
01076       Assert( u8_tmp<CACHE_FBB_SIZE);
01077       MSB(g_cache_fbb.mem[u8_tmp]) = Nfc_rd_data_fetch_next();
01078       LSB(g_cache_fbb.mem[u8_tmp]) = Nfc_rd_data_fetch_next();
01079       Assert( g_cache_fbb.mem[u8_tmp]>=g_nf_first_block );
01080       Assert( g_cache_fbb.mem[u8_tmp]< G_N_BLOCKS       );
01081       byte_addr+=2;
01082       Assert( byte_addr<SIZE_PAGE_BYTE); // Should stay in the page. Algo limitation.
01083    }
01084    g_cache_fbb.ctrl.valid = TRUE;
01085 } // end of nf_cache_fbb_refill
01086 
01087 
01088 
01099 static void nf_cache_lut_flush( void  )
01100 {
01101    _MEM_TYPE_SLOW_ U32  page_addr;
01102    U16  byte_addr;
01103    _MEM_TYPE_SLOW_ U16  sub_lut_log_sz;
01104    _MEM_TYPE_SLOW_ U8   sub_lut_id;
01105    U8   u8_tmp;
01106 
01107    Assert(TRUE==g_cache_lut.ctrl.valid);
01108    Assert(TRUE==g_cache_lut.ctrl.dirty);
01109 
01110    sub_lut_id     = g_cache_lut.first>>(NF_SHIFT_SUBLUT_PHYS-NF_SHIFT_N_DEVICES);
01111    sub_lut_log_sz = ( sub_lut_id==(g_n_sub_lut-1) ) ? g_last_sub_lut_log_sz : g_sub_lut_log_sz ;
01112 
01113    trace("nf_cache_lut_flush;"); trace_hex16(g_lut_block_addr[sub_lut_id]);trace_nl();
01114 
01115    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01116 
01117    page_addr=
01118       nf_block_2_page( g_lut_block_addr[sub_lut_id] )  // base address
01119    +  (U32)(g_lut_block_index[sub_lut_id])             // offset to sub-LUT
01120    ;
01121 
01122    nfc_open_page_read( page_addr, 0);
01123 
01124    for ( byte_addr=0 /* used as block address! */ ; byte_addr<(sub_lut_log_sz*NF_N_DEVICES) ; )
01125    {  // Read the LUT stored in Nand
01126       g_page_buffer[2*byte_addr   ] = Nfc_rd_data_fetch_next();
01127       g_page_buffer[2*byte_addr +1] = Nfc_rd_data_fetch_next();
01128 #if (_ASSERT_==ENABLE)
01129       MSB(_debug)= g_page_buffer[2*byte_addr   ];
01130       LSB(_debug)= g_page_buffer[2*byte_addr +1];
01131       Assert( _debug>=g_nf_first_block );
01132       Assert( _debug< G_N_BLOCKS       );
01133 #endif
01134       byte_addr ++;
01135    }
01136 
01137    // Modify the page
01138    //
01139    byte_addr = // logical position of the block
01140       (  g_cache_lut.first                               // Absolute logical block number...
01141       &  ( (U16)NF_SUBLUT_SIZE/NF_N_DEVICES -1)          // ...Modulo the number of logical block in a LUT
01142       )
01143    *  NF_N_DEVICES*2;
01144 
01145    Assert( byte_addr<2048 );
01146 
01147    for ( u8_tmp=0 ; u8_tmp<(g_cache_lut.last+1-g_cache_lut.first)*NF_N_DEVICES ; u8_tmp++ )
01148    {  // flush the cache buffer in the buffer
01149       Assert( u8_tmp<CACHE_LUT_SIZE );
01150       Assert( byte_addr<(NF_PAGE_BUFFER_SIZE-1) );
01151       Assert( g_cache_lut.mem[u8_tmp]>=g_nf_first_block );
01152       Assert( g_cache_lut.mem[u8_tmp]< G_N_BLOCKS       );
01153       g_page_buffer[byte_addr++] = MSB(g_cache_lut.mem[u8_tmp]) ;
01154       g_page_buffer[byte_addr++] = LSB(g_cache_lut.mem[u8_tmp]) ;
01155    }
01156 
01157    // Program the page
01158    //
01159    g_lut_block_index[sub_lut_id]++;
01160 
01161    if ( g_lut_block_index[sub_lut_id] ==  (1<<G_SHIFT_BLOCK_PAGE) )
01162    { // Need a new block for the flush
01163       _MEM_TYPE_SLOW_ U16 u16_swap;
01164 
01165       if ( FALSE==g_cache_fbb.ctrl.valid ) { nf_cache_fbb_refill(); }
01166 
01167 #define U16_FBB_OFST   ((U16)NF_N_DEVICES*g_cache_fbb.p + S_MNGT_DEV)
01168       Assert( g_cache_fbb.mem[U16_FBB_OFST]>=g_nf_first_block );
01169       Assert( g_cache_fbb.mem[U16_FBB_OFST]< G_N_BLOCKS       );
01170       u16_swap                      = g_lut_block_addr[ sub_lut_id] ;
01171       g_lut_block_addr[ sub_lut_id] = g_cache_fbb.mem[U16_FBB_OFST] ;
01172       g_cache_fbb.mem[U16_FBB_OFST] = u16_swap ;
01173       g_lut_block_index[sub_lut_id] = 0;
01174 #undef U16_FBB_OFST
01175 
01176       trace("nf_cache_lut_flush;swap;"); trace_hex16(g_lut_block_addr[sub_lut_id]);trace_nl();
01177       g_cache_fbb.ctrl.dirty=TRUE;
01178 
01179       nf_write_lut(0, sub_lut_id, sub_lut_log_sz); // TODO: we should test the status returned
01180 
01181       nfc_erase_block( nf_block_2_page( u16_swap ), TRUE );
01182 
01183       g_cache_fbb.p++;
01184       if( g_cache_fbb.p==(g_cache_fbb.max-1) )
01185       { // Only 1 remaining entry in FBB cache
01186          nf_cache_fbb_flush( FALSE ); // No dirty test, since we know that the cache is dirty
01187          nf_cache_fbb_refill();
01188       }
01189    }
01190    else
01191    {
01192       nf_write_lut(0, sub_lut_id, sub_lut_log_sz); // TODO: we should test the status returned
01193    }
01194 
01195    g_cache_lut.ctrl.dirty=FALSE;
01196 
01197    Nf_check_fbb( FALSE );
01198    Nf_check_lut();
01199 } // end of nf_cache_lut_flush
01200 
01201 
01202 
01203 
01204 
01213 Status_bool nf_write_lut(
01214    U8  pos
01215 ,  U8  i_sub_lut
01216 ,  U16 sub_lut_log_sz)
01217 {
01218    U16  block_addr; // Physical block number
01219    U8 _MEM_TYPE_SLOW_ * p_buf=g_page_buffer + (U16)pos*((U16)1<<(G_SHIFT_PAGE_BYTE));
01220 
01221    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01222    // The buffer is built as:
01223    // |    512    |    512    |    512    |    512    |
01224    //
01225    // The page is built as:
01226    // |    512    |    512    |    512    |    512    |SZ|
01227    //
01228    // The LUT fits in a physical page.
01229    //
01230    nfc_open_page_write(
01231       nf_block_2_page( g_lut_block_addr[i_sub_lut] ) // base address
01232    +  (U32)(g_lut_block_index[i_sub_lut])            // offset to sub-LUT
01233    ,  0 );
01234 
01235    trace("nf_write_lut;");trace_hex16(g_lut_block_addr[i_sub_lut]); trace(";"); trace_hex16(g_lut_block_index[i_sub_lut]);trace_nl();
01236    for( block_addr=0 ; block_addr<((U16)1<<(G_SHIFT_PAGE_BYTE-1)) ; block_addr+=1 )
01237    {
01238       if ( block_addr<(sub_lut_log_sz*NF_N_DEVICES) )
01239       {
01240 #if (_ASSERT_==ENABLE)
01241          Assert(           ( block_addr*2)<(NF_PAGE_BUFFER_SIZE-1) );
01242          MSB(_debug)= p_buf[ block_addr*2   ] ;
01243          LSB(_debug)= p_buf[ block_addr*2 +1] ;
01244          Assert( _debug>=g_nf_first_block );
01245          Assert( _debug< G_N_BLOCKS       );
01246 #endif
01247          Nfc_wr_data( p_buf[ block_addr*2   ] );
01248          Nfc_wr_data( p_buf[ block_addr*2 +1] );
01249          trace_hex(p_buf[ block_addr*2   ]);
01250          trace_hex(p_buf[ block_addr*2 +1]);
01251          trace("-");
01252       }
01253       else
01254       {
01255          Nfc_wr_data( 0xFF );
01256          Nfc_wr_data( 0xFF );
01257          trace("FFFF-");
01258       }
01259    }
01260    trace_nl();
01261 
01262    // Write the spare information
01263    //
01264    Nfc_wr_data( 0xFF              );                              // 0- block is valid (for 2048 compatibility)
01265    Nfc_wr_data( NFC_BLK_ID_SUBLUT );                              // 1- sub-LUT
01266    Nfc_wr_data( i_sub_lut         );                              // 2- sub-LUT id
01267    Nfc_wr_data( 0xFF              );                              // 3- unused
01268    Nfc_wr_data( g_n_sub_lut       );                              // 4- number of sub-LUT
01269    Nfc_wr_data( 0xFF              );                              // 5- block is valid (for 512 compatibility)
01270    Nfc_wr_data( MSB(sub_lut_log_sz) );                            // 6-7 Number of log blocks in sub-LUT
01271    Nfc_wr_data( LSB(sub_lut_log_sz) );
01272    Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); // 8-9-10-   ECC2
01273    Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF );                      // 11-12-    LBA
01274    Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); // 13-14-15- ECC1
01275 
01276    Nfc_set_cmd( NF_PAGE_PROGRAM_CMD );
01277    if ( FAIL==nfc_check_status() ) { return FAIL; }
01278 
01279    return PASS;
01280 } // end of nf_write_lut
01281 
01282 
01283 
01295 void nf_cache_fbb_flush( Bool b_ecc_err )
01296 {
01297    _MEM_TYPE_SLOW_ U32  page_addr;
01298    _MEM_TYPE_SLOW_ U16  byte_addr;
01299    _MEM_TYPE_SLOW_ U16 u16_delete=0;
01300    _MEM_TYPE_SLOW_ U16  u16_tmp;
01301    U8   u8_tmp;
01302    _MEM_TYPE_SLOW_ U8   u8_pos;
01303    Bool bool_delete=FALSE;
01304 
01305    Assert(TRUE==g_cache_fbb.ctrl.valid);
01306    Assert(TRUE==g_cache_fbb.ctrl.dirty);
01307    // Assert(g_cache_fbb.p==(g_cache_fbb.max-1)); This is no more the case for ECC error not correctable
01308 
01309    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01310 
01311    trace("nf_cache_fbb_flush;"); trace_hex16(g_fbb_block_addr);trace_nl();
01312 
01313    page_addr=
01314       nf_block_2_page( g_fbb_block_addr  )  // base address
01315    +  (U32)g_fbb_block_index                // offset to page
01316    ;
01317 
01318    g_fbb_block_index++;
01319 
01320    if ( g_fbb_block_index ==  (1<<G_SHIFT_BLOCK_PAGE)/(1<<0) )
01321    {  // Need to recycle the FBB block itself, using a free-block ! This is always possible
01322       // since there is always a free block (.p=.max-1) specially for that purpose.
01323       byte_addr = ((U16)NF_N_DEVICES*g_cache_fbb.p + S_MNGT_DEV);
01324 
01325       Assert( g_cache_fbb.mem[byte_addr]>=g_nf_first_block );
01326       Assert( g_cache_fbb.mem[byte_addr]< G_N_BLOCKS       );
01327       u16_delete                 = g_fbb_block_addr           ;
01328       g_fbb_block_addr           = g_cache_fbb.mem[byte_addr] ;
01329       g_cache_fbb.mem[byte_addr] = u16_delete;
01330       g_fbb_block_index = 0;
01331 
01332       trace("nf_cache_fbb_flush;swap;"); trace_hex16(g_fbb_block_addr);trace_nl();
01333       
01334       // g_cache_fbb.ctrl.dirty=TRUE; This is already the case !
01335 
01336       g_cache_fbb.p++;
01337       bool_delete=TRUE;
01338    }
01339 
01340    if( !b_ecc_err )  { u8_pos = g_cache_fbb.p;   }
01341    else              { u8_pos = g_cache_fbb.max; }
01342 
01343    byte_addr = ((U16)NF_N_DEVICES*2*u8_pos);
01344 
01345    Assert( byte_addr<SIZE_PAGE_BYTE );
01346 
01347    nfc_open_page_read( page_addr, byte_addr);
01348 
01349    Assert( g_cache_fbb.p<=(g_n_free_blocks/NF_N_DEVICES) );
01350    for (
01351       u16_tmp=0
01352    ;  u16_tmp<((g_n_free_blocks/NF_N_DEVICES)-u8_pos)*NF_N_DEVICES*2
01353    ; )
01354    {  // Move the free-blocks after <pos> to the beginning of the buffer.
01355       Assert( u16_tmp<(NF_PAGE_BUFFER_SIZE-3) );
01356       g_page_buffer[u16_tmp++] = Nfc_rd_data_fetch_next();
01357       g_page_buffer[u16_tmp++] = Nfc_rd_data_fetch_next();
01358 #if (_ASSERT_==ENABLE)
01359       MSB(_debug)= g_page_buffer[u16_tmp-2];
01360       LSB(_debug)= g_page_buffer[u16_tmp-1];
01361       Assert( _debug>=g_nf_first_block );
01362       Assert( _debug< G_N_BLOCKS       );
01363 #endif
01364    }
01365 
01366    for ( u8_tmp=0 ; u8_tmp<(u8_pos*NF_N_DEVICES); u8_tmp++ )
01367    {  // Then add the cache content
01368       Assert( u8_tmp < CACHE_FBB_SIZE );
01369       Assert( u16_tmp< NF_FULL_PAGE_BUFFER_SIZE );
01370 #if (_ASSERT_==ENABLE)
01371       // When coming from ECC 2-bits error, an entry has been removed
01372       // from the cache, so the last entry is 0xffff
01373       if( !b_ecc_err )
01374       {
01375          Assert( g_cache_fbb.mem[u8_tmp]>=g_nf_first_block );
01376          Assert( g_cache_fbb.mem[u8_tmp]< G_N_BLOCKS       );
01377       }
01378 #endif
01379       g_page_buffer[u16_tmp++] = MSB(g_cache_fbb.mem[u8_tmp]);
01380       g_page_buffer[u16_tmp++] = LSB(g_cache_fbb.mem[u8_tmp]);
01381    }
01382 #if (_ASSERT_==ENABLE)
01383    // Ensure that, when there is no fbb recycle, the blocks in the cache at
01384    // position p are identical to the blocks in the beginning of the new line.
01385    if( (FALSE==bool_delete) && ( !b_ecc_err ))
01386    {
01387       for ( u8_tmp=0 ; u8_tmp<NF_N_DEVICES ; u8_tmp++ )
01388       {
01389          MSB(_debug)= g_page_buffer[u8_tmp*2   ];
01390          LSB(_debug)= g_page_buffer[u8_tmp*2 +1];
01391          Assert( _debug==g_cache_fbb.mem[(g_cache_fbb.p)*NF_N_DEVICES + u8_tmp] );
01392       }
01393    }
01394 #endif
01395 
01396    nf_write_fbb(); // Should test the result
01397    Nf_check_fbb( b_ecc_err );
01398    Nf_check_lut();
01399 
01400    if( TRUE==bool_delete )
01401    {
01402       nfc_erase_block( nf_block_2_page( u16_delete ), TRUE );
01403    }
01404 
01405    Assert( u16_tmp==(g_n_free_blocks*2) ); // All the list should have been processed
01406    g_cache_fbb.ctrl.dirty=FALSE;
01407 } // end of nf_cache_fbb_flush
01408 
01409 
01410 
01417 Status_bool nf_write_fbb( void )
01418 {
01419    U16 u16_tmp;
01420 
01421    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01422    nfc_open_page_write(
01423       nf_block_2_page( g_fbb_block_addr )  // base address
01424    +  (U32)g_fbb_block_index               // offset to Free-blocks block entry
01425    , 0 );
01426    for ( u16_tmp=0 ; u16_tmp<((U16)1<<(G_SHIFT_PAGE_BYTE-1)) ; )
01427    {
01428       if ( u16_tmp<g_n_free_blocks )
01429       {
01430          Nfc_wr_data( g_page_buffer[2*u16_tmp   ] );
01431          Nfc_wr_data( g_page_buffer[2*u16_tmp +1] );
01432       }
01433       else
01434       {
01435          Nfc_wr_data( 0xFF );
01436          Nfc_wr_data( 0xFF );
01437       }
01438       u16_tmp++;
01439    }
01440    // Write the spare information
01441    //
01442    Nfc_wr_data( 0xFF );                                           // 0- block is valid (for 2048 compatibility)
01443    Nfc_wr_data( NFC_BLK_ID_FBB );                                 // 1- Free-blocks block
01444    Nfc_wr_data( MSB(g_n_free_blocks));                            // 2-3 Number of free blocks
01445    Nfc_wr_data( LSB(g_n_free_blocks));
01446    Nfc_wr_data( NFC_OFST_4_FBB_DRIVER_RELEASE );                  // 4- Nand-Flash driver ID
01447    Nfc_wr_data( 0xFF );                                           // 5- block is valid (for 512 compatibility)
01448    Nfc_wr_data( NFC_OFST_6_FBB_VALID );                           // 6- FBB-LUTs valid
01449    Nfc_wr_data( 0xFF );                                           // 7- Unused
01450    Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); // 8-9-10-   Unused
01451    Nfc_wr_data( MSB(g_n_export_blocks));                          // 11-12- Number of exported blocks
01452    Nfc_wr_data( LSB(g_n_export_blocks));
01453    Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); Nfc_wr_data( 0xFF ); // 13-14-15- Unused
01454 
01455    Nfc_set_cmd( NF_PAGE_PROGRAM_CMD );
01456    if ( FAIL==nfc_check_status() ) { return FAIL; }
01457    return PASS;
01458 } // end of nf_write_fbb
01459 
01460 
01461 
01462 #if (_ASSERT_==ENABLE)
01463 static void nf_check_fbb( Bool b_ecc_err )
01464 {
01465    U16 u16_tmp;
01466 
01467    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01468    trace("nf_check_fbb\n\r");
01469    trace("g_fbb_block_addr "); trace_hex16(g_fbb_block_addr);
01470    trace("\n\rs_fbb_block_index= "); trace_hex(g_fbb_block_index); trace("\n\r");
01471    nfc_open_page_read(
01472       nf_block_2_page( g_fbb_block_addr )  // base address
01473    +  (U32)g_fbb_block_index               // offset to Free-blocks block entry
01474    , 0 );
01475    trace("n free blocks: "); trace_u16(g_n_free_blocks); trace_nl();
01476    for ( u16_tmp=0 ; u16_tmp<g_n_free_blocks ; )
01477    {
01478 #if (_TRACE_==ENABLE)
01479       if( u16_tmp>=2048 ) break;
01480       if( !(u16_tmp% 8) ) {
01481          trace("\n\r");
01482          trace_u16(u16_tmp);
01483       }
01484 #endif
01485       MSB(_debug)= Nfc_rd_data_fetch_next();
01486       LSB(_debug)= Nfc_rd_data_fetch_next();
01487       trace(" 0x"); trace_hex( MSB(_debug) ); trace_hex( LSB(_debug) );
01488       // When coming from ECC 2-bits error, an entry has been removed
01489       // from the cache, so the last entry is 0xffff
01490       if( !b_ecc_err )
01491       {
01492          Assert( _debug>=g_nf_first_block );
01493          Assert( _debug< G_N_BLOCKS       );
01494       }
01495 #if 0
01496       This tests have been commented out: when the cache are dirty, we can not just check the memory
01497       with possible protected block address (fbb, lut).
01498       Ex: FBB is dirty, a recycle have been done between on of the free block and g_lut_block_addr[x].
01499       In the FBB memory, the (new) lut address is still present, even if it is not the case in the cache.
01500       if ( (u16_tmp%NF_N_DEVICES)==S_MNGT_DEV )
01501       { // Check dangerous address collision for NF_MNGT only
01502          Assert( _debug!=g_fbb_block_addr );
01503          for ( u8_tmp=0 ; u8_tmp<g_n_sub_lut ; u8_tmp++ ) {
01504             Assert( _debug!=g_lut_block_addr[u8_tmp] );
01505          }
01506       }
01507 #endif
01508       u16_tmp++;
01509    }
01510    trace_nl();
01511 } // nf_check_fbb
01512 
01513 
01514 static void nf_check_lut( void )
01515 {
01516    U16 u16_tmp;
01517    U8  sub_lut_id;
01518    U16 sub_lut_log_sz;
01519 
01520    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
01521    for ( sub_lut_id=0 ; sub_lut_id<g_n_sub_lut ; sub_lut_id++ )
01522    {
01523       nfc_open_page_read(
01524          nf_block_2_page( g_lut_block_addr[sub_lut_id] ) // base address
01525       +  (U32)g_lut_block_index[sub_lut_id]              // offset to LUT block entry
01526       , 0 );
01527 
01528       sub_lut_log_sz = ( sub_lut_id==(g_n_sub_lut-1) ) ? g_last_sub_lut_log_sz : g_sub_lut_log_sz ;
01529       for ( u16_tmp=0 ; u16_tmp<(sub_lut_log_sz*NF_N_DEVICES) ; )
01530       {
01531          MSB(_debug)= Nfc_rd_data_fetch_next();
01532          LSB(_debug)= Nfc_rd_data_fetch_next();
01533          Assert( _debug>=g_nf_first_block );
01534          Assert( _debug< G_N_BLOCKS       );
01535 #if 0
01536          if ( (u16_tmp%NF_N_DEVICES)==S_MNGT_DEV )
01537          { // Check dangerous address collision for NF_MNGT only
01538             Assert( _debug!=g_fbb_block_addr );
01539             for ( u8_tmp=0 ; u8_tmp<g_n_sub_lut ; u8_tmp++ ) {
01540                Assert( _debug!=g_lut_block_addr[u8_tmp] );
01541             }
01542          }
01543 #endif
01544          u16_tmp++;
01545       }
01546    }
01547 }
01548 #endif
01549 
01550 
01551 
01552 // Here are the variable supposed to be initialized:
01553 //    g_curr_dev_id
01554 //    s_curr_log_sector
01555 //    g_block_to_kill[] block addr
01556 //    g_phys_page_addr[] page addr
01557 //
01558 void nf_copy_tail(void)
01559 {
01560    _MEM_TYPE_SLOW_ U8  u8_tmp;
01561                    U8  u8_tmp2;
01562    _MEM_TYPE_SLOW_ U16 u16_tmp;
01563    _MEM_TYPE_SLOW_ U16 byte_addr;
01564 
01565    // Test if we do not reach the end of the logical block
01566    //
01567    if( 0!=((U16)g_last_log_sector & ( ((U16)1<<(S_SHIFT_LOG_BLOCK_SECTOR)) -1)) )
01568    {
01569       trace("nf_copy_tail;"); trace_hex32(g_last_log_sector); trace_nl();
01570       if( Is_not_nf_512() )
01571       {  // Following is not possible on 512B Nand
01572 
01573          u8_tmp = // current offset sector in the current page
01574             LSB0(g_last_log_sector)
01575          &  ( SIZE_PAGE_SECTOR-1 )
01576          ;
01577 
01578          u8_tmp2 = SIZE_PAGE_SECTOR -u8_tmp;
01579          if( 0!=u8_tmp )
01580          {  // Copy the rest of the current line
01581 
01582             byte_addr=((U16)u8_tmp) * (SIZE_SECTOR_BYTE);
01583             Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);  // open the current device
01584             nfc_open_page_read(                                                       // Open the old block at :
01585                   nf_block_2_page( g_block_to_kill[g_curr_dev_id] )                   // adresse of the beginning of the old block
01586                +  (LSB0(g_phys_page_addr[g_curr_dev_id])&(SIZE_BLOCK_PAGE -1))        // current offset page in the old and new block
01587             ,  byte_addr );                                                           // current offset sector in the current page
01588             // for each sector in the physical page
01589             u16_tmp = u8_tmp2 * SIZE_SECTOR_BYTE;
01590             g_last_log_sector += u8_tmp2;                                             // update the current logical sector
01591 
01592             // read the sector of the old page
01593             nf_upload(g_page_buffer+byte_addr, u16_tmp/16 );
01594 
01595             // Read the associated spare zone
01596             byte_addr= NF_SPARE_POS + (((U16)u8_tmp)*16);
01597             nfc_open_page_read(                                                       // Open the old block at :
01598                   nf_block_2_page( g_block_to_kill[g_curr_dev_id] )                   // adresse of the beginning of the old block
01599                +  (LSB0(g_phys_page_addr[g_curr_dev_id])&(SIZE_BLOCK_PAGE -1))        // current offset page in the old and new block
01600             ,  byte_addr );                                                           // current offset sector in the current page
01601             nf_upload(g_page_buffer+byte_addr, u8_tmp2 );
01602 
01603             byte_addr=((U16)u8_tmp) * (SIZE_SECTOR_BYTE);
01604             nfc_open_page_write( // Open the new block at the current position
01605                g_phys_page_addr[g_curr_dev_id]
01606             ,  byte_addr );
01607 
01608             // write the sector in the new page
01609             nf_download(g_page_buffer+byte_addr, (U8)(u16_tmp/16) );
01610 
01611             // write the associated spare zone
01612             byte_addr=NF_SPARE_POS + (((U16)u8_tmp)*16);
01613             Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
01614             Nfc_set_adc( (byte_addr)%256 );
01615             Nfc_set_adc( (byte_addr)/256 );
01616             nf_download(g_page_buffer+byte_addr, u8_tmp2 );
01617             Nfc_set_cmd(NF_PAGE_PROGRAM_CMD);
01618 
01619             g_phys_page_addr[g_curr_dev_id]++;                                                   // update the current physical page of the current device
01620             g_curr_dev_id++;                                                                     // update the current device
01621             if( g_curr_dev_id==NF_N_DEVICES ) { g_curr_dev_id=0; }
01622          }
01623       }
01624 
01625       // then copy the rest of the logical block
01626       //
01627       while( 0!=((U16)g_last_log_sector & (((U16)1<<(S_SHIFT_LOG_BLOCK_SECTOR))-1)) )
01628       {
01629          Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);  // open the current device
01630 
01631          g_copy_src=
01632             nf_block_2_page(g_block_to_kill[g_curr_dev_id])                     // adresse of the beginning of the old block
01633          +  (LSB0(g_phys_page_addr[g_curr_dev_id])&(SIZE_BLOCK_PAGE -1))        // current offset page in the old and new block
01634          ;
01635          nf_copy(g_phys_page_addr[g_curr_dev_id]);
01636          g_phys_page_addr[g_curr_dev_id]++;
01637 
01638          g_last_log_sector+=SIZE_PAGE_SECTOR;                            // update the current logical sector
01639          g_curr_dev_id++;                                                          // update the current device
01640          if( g_curr_dev_id==NF_N_DEVICES ) { g_curr_dev_id=0; }
01641       }
01642 
01643       // Delete old blocks
01644       //
01645       nf_erase_old_blocks();
01646    }else{
01647       trace("nf_copy_tail empty??;"); trace_hex32(g_last_log_sector); trace_nl();
01648    }
01649    g_last_log_sector= 0xFFFFFFFF;
01650 }
01651 
01652 
01653 
01663 void nf_download(U8 _MEM_TYPE_SLOW_* datbuf, U8 loop)
01664 {
01665   U8 _MEM_TYPE_SLOW_ * tempbuf = datbuf;
01666   U8 i = loop;
01667 
01668   while (i != 0)
01669   {
01670      Nf_wr_byte(*(tempbuf)); tempbuf++;
01671      Nf_wr_byte(*(tempbuf)); tempbuf++;
01672      Nf_wr_byte(*(tempbuf)); tempbuf++;
01673      Nf_wr_byte(*(tempbuf)); tempbuf++;
01674      Nf_wr_byte(*(tempbuf)); tempbuf++;
01675      Nf_wr_byte(*(tempbuf)); tempbuf++;
01676      Nf_wr_byte(*(tempbuf)); tempbuf++;
01677      Nf_wr_byte(*(tempbuf)); tempbuf++;
01678      Nf_wr_byte(*(tempbuf)); tempbuf++;
01679      Nf_wr_byte(*(tempbuf)); tempbuf++;
01680      Nf_wr_byte(*(tempbuf)); tempbuf++;
01681      Nf_wr_byte(*(tempbuf)); tempbuf++;
01682      Nf_wr_byte(*(tempbuf)); tempbuf++;
01683      Nf_wr_byte(*(tempbuf)); tempbuf++;
01684      Nf_wr_byte(*(tempbuf)); tempbuf++;
01685      Nf_wr_byte(*(tempbuf)); tempbuf++;
01686      i--;
01687   }
01688 }
01689 
01690 
01691 
01699 void nf_upload(U8 _MEM_TYPE_SLOW_* datbuf, U8 loop)
01700 {
01701   U8 _MEM_TYPE_SLOW_ * tempbuf = datbuf;
01702   U8 i = loop;
01703 
01704   while (i != 0)
01705   {
01706      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01707      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01708      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01709      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01710      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01711      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01712      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01713      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01714      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01715      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01716      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01717      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01718      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01719      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01720      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01721      *(tempbuf) = Nf_rd_byte(); tempbuf++;
01722      i--;
01723   }
01724 }
01725 
01726 
01743 static void nf_translate( Nf_translate_mode mode )
01744 {
01745    _MEM_TYPE_MEDFAST_ U8  u8_tmp   = (s_curr_log_sector & (SIZE_PAGE_SECTOR -1) );
01746    _MEM_TYPE_MEDFAST_ U8  u8_shift;
01747    _MEM_TYPE_MEDFAST_ U8  u8_curr_page;
01748    _MEM_TYPE_MEDFAST_ U8  u8_last_page;
01749 
01750    // Here begins the translation:
01751    // logical sector number (s_curr_log_sector):
01752    //
01753    // -> logical block number       (g_log_block_id)
01754    // -> device number              (g_curr_dev_id)
01755    // -> position in page           (s_curr_n_byte)
01756    // -> nb of sectors in first page(s_nb_sectors_step)
01757    //
01758    g_log_block_id    =  s_curr_log_sector >> S_SHIFT_LOG_BLOCK_SECTOR;
01759    g_curr_dev_id     = (s_curr_log_sector >> (G_SHIFT_PAGE_BYTE - S_SHIFT_SECTOR_BYTE)) % NF_N_DEVICES;
01760    s_curr_n_byte     = ((U16)u8_tmp) << S_SHIFT_SECTOR_BYTE;
01761    s_nb_sectors_step = SIZE_PAGE_SECTOR - u8_tmp;
01762    s_nb_sectors_step = Min(s_n_sectors, s_nb_sectors_step); // Adapt if nb sector to read is lower than a page
01763 
01764 //   Nfc_put_lba(g_log_block_id);
01765 
01766    Nf_check_fbb( FALSE );
01767    Nf_check_lut();
01768 
01769    if ( TRUE==g_cache_lut.ctrl.valid )
01770    {
01771       if( NF_TRANS_FLUSH==mode )
01772       {
01773          if ( TRUE==g_cache_lut.ctrl.dirty )
01774          {
01775             nf_cache_lut_flush();
01776             nf_cache_lut_refill(g_log_block_id);
01777          }
01778       }
01779 
01780       if(( g_log_block_id<g_cache_lut.first )
01781       || ( g_log_block_id>g_cache_lut.last  ))
01782       { // MISS: need to refill the cache
01783 
01784          if ( TRUE==g_cache_lut.ctrl.dirty ) { nf_cache_lut_flush(); }
01785          nf_cache_lut_refill(g_log_block_id);
01786       }
01787    }
01788    else { nf_cache_lut_refill(g_log_block_id); } // The cache is not valid. Just re-fill it.
01789 
01790 
01791 
01792    if ( TRUE==g_cache_fbb.ctrl.valid )
01793    {
01794       if( NF_TRANS_FLUSH==mode )
01795       {
01796          if ( TRUE==g_cache_fbb.ctrl.dirty )
01797          {
01798             nf_cache_fbb_flush( FALSE );
01799             nf_cache_fbb_refill();
01800          }
01801       }
01802    }
01803    else { nf_cache_fbb_refill(); }
01804 
01805 
01806 
01807    u8_curr_page = (g_log_block_id-g_cache_lut.first)*NF_N_DEVICES;
01808    u8_last_page = (U16)g_cache_fbb.p*NF_N_DEVICES;
01809 
01810    for( u8_tmp=0 ; u8_tmp<NF_N_DEVICES ; u8_tmp++, u8_curr_page++, u8_last_page++)
01811    {
01812       if( NF_TRANS_SWAP==mode )
01813       {
01814          nf_swap(u8_tmp, u8_curr_page, u8_last_page);
01815       }
01816 
01817       g_phys_page_addr[u8_tmp] = nf_block_2_page( g_cache_lut.mem[u8_curr_page] ); // ... Then adapt it to page number
01818    }
01819 
01820    if( NF_TRANS_SWAP==mode )
01821    {
01822       g_cache_fbb.p++;
01823       if( g_cache_fbb.p==(g_cache_fbb.max-1) )
01824       { // Only 1 remaining entry in FBB cache
01825          nf_cache_fbb_flush( FALSE ); // No dirty test, since we know that the cache is dirty
01826          nf_cache_fbb_refill();
01827       }
01828    }
01829    else
01830    {
01831       // Build the physical memory address
01832       //
01833       u8_shift =                                          // page offset is
01834          ( s_curr_log_sector >> S_SHIFT_LOG_PAGE_SECTOR ) // convert sector id to page id
01835       &  ( SIZE_BLOCK_PAGE  -1                          ) // modulo number of phys pages in a phys block
01836       ;
01837 
01838       for ( u8_tmp=0 ; u8_tmp<NF_N_DEVICES ; u8_tmp++ )
01839       {
01840          if ( u8_tmp<g_curr_dev_id ) { g_phys_page_addr[u8_tmp] +=  u8_shift + 1 ; } // already read
01841          else                        { g_phys_page_addr[u8_tmp] +=  u8_shift     ; } // to be read
01842       }
01843    }
01844 
01845    g_next_phys_page_addr=g_phys_page_addr[g_curr_dev_id];
01846    trace("nf_translate;g_phys_page_addr["); trace_u8(g_curr_dev_id); trace("] = "); trace_hex32(g_phys_page_addr[g_curr_dev_id]); trace_nl();
01847 }
01848 
01849 
01850 
01859 void nf_copy( U32 copy_dst )
01860 {
01861    Bool b_copy_fast;
01862    U8   zone_A, zone_B;
01863 
01864    // Compute the possibility of fast copy
01865    if( 0 == G_COPY_BACK_CONT )
01866    {
01867       b_copy_fast = 0;     // never possible
01868    }
01869    else
01870    {
01871       if( (1 == G_COPY_BACK_CONT) && (1==G_COPY_BACK_DISCONT) )
01872       {
01873          b_copy_fast = 1;  // always possible
01874       }
01875       else
01876       {
01877          // Check block address
01878          b_copy_fast = 1;  // by default possible
01879          if( 1 != G_COPY_BACK_CONT )
01880          {
01881 /*
01882             zone_A = (g_copy_src>>G_SHIFT_BLOCK_PAGE) / ((U16)G_N_BLOCKS/G_COPY_BACK_CONT);
01883             zone_B = (copy_dst  >>G_SHIFT_BLOCK_PAGE) / ((U16)G_N_BLOCKS/G_COPY_BACK_CONT);
01884 */
01885             // block_zone = page add / number of page / 1024
01886             if( Is_nf_2k() )
01887             {
01888                // block_zone = (page add >> (G_SHIFT_BLOCK_PAGE + 10)) / (G_N_ZONES/G_COPY_BACK_CONT);
01889                // block_zone = ((page add >> 16) * G_COPY_BACK_CONT) / G_N_ZONES;
01890                zone_A = (MSB1(g_copy_src)*G_COPY_BACK_CONT)/G_N_ZONES;
01891                zone_B = (MSB1(copy_dst  )*G_COPY_BACK_CONT)/G_N_ZONES;
01892             }else{
01893                // block_zone = page add >> (G_SHIFT_BLOCK_PAGE + 10) / (G_N_ZONES/G_COPY_BACK_CONT);
01894                zone_A = ((U8)(g_copy_src>>(G_SHIFT_BLOCK_PAGE + 10)) *G_COPY_BACK_CONT) /G_N_ZONES;
01895                zone_B = ((U8)(copy_dst  >>(G_SHIFT_BLOCK_PAGE + 10)) *G_COPY_BACK_CONT) /G_N_ZONES;
01896             }
01897             if( zone_A != zone_B )
01898                b_copy_fast = 0;     // no possible
01899          }
01900          if( 1 != G_COPY_BACK_DISCONT )
01901          {
01902 // define mandatory to delete compile error on MODULO 0
01903 #if (NF_GENERIC_DRIVER==TRUE) || (NF_AUTO_DETECT_2KB==TRUE) || (NF_AUTO_DETECT_512B==TRUE)
01904             zone_A = ((U16)g_copy_src>>G_SHIFT_BLOCK_PAGE) % G_COPY_BACK_DISCONT;
01905             zone_B = ((U16)copy_dst  >>G_SHIFT_BLOCK_PAGE) % G_COPY_BACK_DISCONT;
01906 #elif ( G_COPY_BACK_DISCONT != 0 )
01907             zone_A = ((U16)g_copy_src>>G_SHIFT_BLOCK_PAGE) % G_COPY_BACK_DISCONT;
01908             zone_B = ((U16)copy_dst  >>G_SHIFT_BLOCK_PAGE) % G_COPY_BACK_DISCONT;
01909 #endif
01910             if( zone_A != zone_B )
01911                b_copy_fast = 0;     // no possible
01912          }
01913       }
01914    }
01915       
01916    // Start copy
01917    if( !b_copy_fast )
01918    {
01919       // copy the page of the old block in buffer
01920       nfc_open_page_read( g_copy_src, 0 );
01921       nf_upload(                                // Works by packet of 16 bytes
01922          g_page_buffer
01923       ,     ((U16)1<<(G_SHIFT_PAGE_BYTE-4))     // Data zone (Page size / 16)
01924          +  ((U16)1<<(G_SHIFT_PAGE_BYTE-5-4))); // Spare zone (Page size / 32 / 16)
01925 
01926       // Add LBA markers to help recovery function
01927       // Need to explain a bit why LBA are written: 
01928       // nf_copy is called from copy_head and copy_tail.
01929       // - copy_head: need to write all the LBA of the pages to help recovery finding
01930       //   where the last sector is written.
01931       //   Moreover, in case that nf_copy is called from copy_head and source block at page 0
01932       //   does not contain LBA.
01933       // - copy_tail: no need to mark the last LBA of the last page to identify the source
01934       //   block since we use another method
01935       g_page_buffer[NF_SPARE_POS+NFC_SPARE_OFST_3_BYTE_3] = NFC_OFST_3_DATA_DST;  // 3- [SW] Source block (recovery) (HW capability not used)
01936       g_page_buffer[NF_SPARE_POS+NFC_SPARE_OFST_6_LBA   ] = MSB(g_log_block_id);  // 6- LBA
01937       g_page_buffer[NF_SPARE_POS+NFC_SPARE_OFST_6_LBA+1 ] = LSB(g_log_block_id);  // 7- LBA
01938       if( Is_nf_2k() )
01939       {
01940          g_page_buffer[NF_SPARE_POS +16*1 +NFC_SPARE_OFST_6_LBA  ] =
01941          g_page_buffer[NF_SPARE_POS +16*2 +NFC_SPARE_OFST_6_LBA  ] =
01942          g_page_buffer[NF_SPARE_POS +16*3 +NFC_SPARE_OFST_6_LBA  ] = MSB(g_log_block_id);  // 6- LBA
01943          g_page_buffer[NF_SPARE_POS +16*1 +NFC_SPARE_OFST_6_LBA+1] =
01944          g_page_buffer[NF_SPARE_POS +16*2 +NFC_SPARE_OFST_6_LBA+1] =
01945          g_page_buffer[NF_SPARE_POS +16*3 +NFC_SPARE_OFST_6_LBA+1] = LSB(g_log_block_id);  // 7- LBA
01946       }
01947 
01948       // copy the buffer in the page of the new block
01949       nfc_open_page_write( copy_dst, 0 );
01950       nf_download(                                // Works by packet of 16 bytes
01951          g_page_buffer
01952       ,     ((U16)1<<(G_SHIFT_PAGE_BYTE-4))       // Data zone (Page size / 16)
01953          +  ((U16)1<<(G_SHIFT_PAGE_BYTE-5-4)));  // Spare zone (Page size / 32 / 16)
01954       Nfc_set_cmd(NF_PAGE_PROGRAM_CMD);
01955    }
01956    else
01957    {
01958       nfc_copy_back_init( g_copy_src );
01959 
01960       Nfc_unprotect_all_flash();                              // WP may be actif due to block protection
01961       Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
01962       Nfc_set_adc( (NF_SPARE_POS+NFC_SPARE_OFST_3_BYTE_3)%256 );
01963       Nfc_set_adc( (NF_SPARE_POS+NFC_SPARE_OFST_3_BYTE_3)/256 );
01964       Nfc_set_adr( LSB0(copy_dst) );
01965       Nfc_set_adr( LSB1(copy_dst) );
01966       if ( 3==G_N_ROW_CYCLES )
01967       {
01968          Nfc_set_adr( MSB1(copy_dst) );
01969       }
01970 
01971       // Remove Source block mask
01972       Nfc_wr_data( NFC_OFST_3_DATA_DST );
01973 
01974       // Add LBA markers to help recovery function
01975       Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
01976       Nfc_set_adc( (NF_SPARE_POS+NFC_SPARE_OFST_6_LBA)%256 );
01977       Nfc_set_adc( (NF_SPARE_POS+NFC_SPARE_OFST_6_LBA)/256 );
01978       Nfc_wr_data( MSB(g_log_block_id) );
01979       Nfc_wr_data( LSB(g_log_block_id) );
01980 
01981       if( Is_nf_2k() )
01982       {
01983          Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
01984          Nfc_set_adc( (NF_SPARE_POS + 16*1 +NFC_SPARE_OFST_6_LBA)%256 );
01985          Nfc_set_adc( (NF_SPARE_POS + 16*1 +NFC_SPARE_OFST_6_LBA)/256 );
01986          Nfc_wr_data( MSB(g_log_block_id) );
01987          Nfc_wr_data( LSB(g_log_block_id) );
01988 
01989          Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
01990          Nfc_set_adc( (NF_SPARE_POS + 16*2 +NFC_SPARE_OFST_6_LBA)%256 );
01991          Nfc_set_adc( (NF_SPARE_POS + 16*2 +NFC_SPARE_OFST_6_LBA)/256 );
01992          Nfc_wr_data( MSB(g_log_block_id) );
01993          Nfc_wr_data( LSB(g_log_block_id) );
01994 
01995          Nfc_set_cmd(NF_RANDOM_DATA_INPUT_CMD);
01996          Nfc_set_adc( (NF_SPARE_POS + 16*3 +NFC_SPARE_OFST_6_LBA)%256 );
01997          Nfc_set_adc( (NF_SPARE_POS + 16*3 +NFC_SPARE_OFST_6_LBA)/256 );
01998          Nfc_wr_data( MSB(g_log_block_id) );
01999          Nfc_wr_data( LSB(g_log_block_id) );
02000       }
02001       Nfc_set_cmd(NF_PAGE_PROGRAM_CMD);
02002    }
02003 }
02004 
02005 
02006 
02021 void nf_swap(U8 dev_id, U8 u8_ofst_lut, U8 u8_ofst_fbb)
02022 {
02023    Assert( dev_id      < NF_N_DEVICES  );
02024    Assert( u8_ofst_lut < CACHE_LUT_SIZE);
02025    Assert( u8_ofst_fbb < CACHE_FBB_SIZE);
02026    Assert( g_cache_lut.mem[u8_ofst_lut]  >=g_nf_first_block );
02027    Assert( g_cache_lut.mem[u8_ofst_lut]  < G_N_BLOCKS       );
02028    Assert( g_cache_fbb.mem[u8_ofst_fbb]  >=g_nf_first_block );
02029    Assert( g_cache_fbb.mem[u8_ofst_fbb]  < G_N_BLOCKS       );
02030    g_block_to_kill[dev_id     ] = g_cache_lut.mem[u8_ofst_lut] ;
02031    g_cache_lut.mem[u8_ofst_lut] = g_cache_fbb.mem[u8_ofst_fbb] ;
02032    g_cache_fbb.mem[u8_ofst_fbb] = g_block_to_kill[dev_id]      ;
02033    trace("g_cache_lut.mem["); trace_u8(u8_ofst_lut); trace("] = "); trace_hex32(g_cache_lut.mem[u8_ofst_lut]); trace_nl();
02034    trace("g_cache_fbb.mem["); trace_u8(u8_ofst_fbb); trace("] = "); trace_hex32(g_cache_fbb.mem[u8_ofst_fbb]); trace_nl();
02035 
02036    // both FBB and LUT caches becomes invalid
02037    g_cache_lut.ctrl.dirty=TRUE;
02038    g_cache_fbb.ctrl.dirty=TRUE;
02039 }
02040 
02041 
02042 
02053 void nf_usb_stop(void)
02054 {
02055 #if (NF_XMCR_MODULE_SHARED == ENABLED)
02056    nf_XMCR_enable();
02057 #endif
02058 
02059    if ( 0xFFFFFFFF!=g_last_log_sector )
02060    {
02061       Nf_access_signal_on();
02062       nf_copy_tail();
02063 
02064       if ( TRUE==g_cache_lut.ctrl.dirty )
02065       { 
02066          nf_cache_lut_flush();
02067          nf_cache_lut_refill(0);
02068       }
02069       if ( TRUE==g_cache_fbb.ctrl.dirty )
02070       {
02071          nf_cache_fbb_flush( FALSE );
02072          nf_cache_fbb_refill();
02073       }
02074       Nf_access_signal_off();
02075    }
02076 
02077 #if (NF_XMCR_MODULE_SHARED == ENABLED)
02078    nf_XMCR_disable();
02079 #endif
02080 }
02081 #endif // NF_BAD_CONFIG
02082 
02083 
02084 
02085 
02086 
02087 //_________________D E B U G    F U N C T I O N S __________________________________
02088 // Only required for debug purpose
02089 
02090 // Erase all the blocks of the memory
02091 void nf_erase_all_blocks(void)
02092 {
02093   U16 i_block;
02094 
02095   for (i_block = G_N_BLOCKS ; i_block != 0 ; i_block--)
02096   {
02097     nfc_erase_block( nf_block_2_page(i_block), TRUE );
02098   }
02099 }
02100 
02101 //_________________R A M   A C C E S S   F U N C T I O N S _____________________
02102 
02103 
02117 Ctrl_status    nf_ram_2_nf(U32 addr, U8 *ram)
02118 {
02119   Ctrl_status tmp_bool;
02120   U16 i;
02121 
02122 #if (NF_XMCR_MODULE_SHARED == ENABLED)
02123    nf_XMCR_enable();
02124 #endif
02125 
02126    s_n_sectors       = 1;
02127    s_curr_log_sector = addr;
02128    s_save_log_addr   = addr + 1;
02129    g_fatal           = FALSE;
02130    s_mem             = TRUE;
02131    s_start           = TRUE;
02132 
02133    // First write operation
02134    Nf_access_signal_on();
02135    if(( s_curr_log_sector==g_last_log_sector )                                           // New write is just after to the last write
02136    && (!(  ( 0==((U16)g_last_log_sector & ( ((U16)1<<(S_SHIFT_LOG_BLOCK_SECTOR)) -1)))   // Not on a logical block boundary
02137       && ( g_curr_dev_id==0                                                        ))))
02138    {
02139       nf_translate( NF_TRANS_NORMAL );
02140       Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);  // open the current device
02141       nfc_open_page_write( g_next_phys_page_addr, s_curr_n_byte );
02142    }
02143    else
02144    {      
02145       nf_open_write( TRUE );
02146    }
02147    
02148    for(i=0;i<512;i++)
02149    {
02150       Nf_wr_byte(*ram);
02151       ram++;
02152    }
02153 
02154    if (Is_nf_2k())
02155    {
02156       nf_update_spare_zone((U8)(1<<(G_SHIFT_PAGE_BYTE - S_SHIFT_SECTOR_BYTE))-s_nb_sectors_step, s_nb_sectors_step);    // update the spare zone once the page has been filled in
02157    }
02158    else
02159    {
02160      nf_update_spare_zone(0, 1);    // update the spare zone once the page has been filled in
02161    }
02162    nf_xfer_update_vars();
02163 
02164    tmp_bool = nf_dfc_write_stop(0);   // ends write operations with "nf_dfc_write_stop(0)" that save the current environnement
02165    Nf_access_signal_off();
02166 
02167 #if (NF_XMCR_MODULE_SHARED == ENABLED)
02168    nf_XMCR_disable();
02169 #endif
02170 
02171    return tmp_bool;
02172 }
02173 
02186 Ctrl_status    nf_nf_2_ram(U32 addr, U8 *ram)
02187 {
02188   U16 i;
02189 
02190 #if (NF_XMCR_MODULE_SHARED == ENABLED)
02191    nf_XMCR_enable();
02192 #endif
02193 
02194    s_n_sectors       = 1;
02195    s_curr_log_sector = addr;
02196    s_save_log_addr   = addr + 1;
02197    g_fatal           = FALSE;
02198    s_mem             = TRUE;
02199    s_start           = TRUE;
02200 
02201    // First read operation
02202    Nf_access_signal_on();
02203    nf_open_read(TRUE);
02204    Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);
02205    nfc_open_page_read( g_phys_page_addr[g_curr_dev_id], s_curr_n_byte );
02206    s_nb_sectors_step = (U8)                              // determine number of sectors to be read
02207                        (Min(                             // on this first page
02208                              1,
02209                              ((1<<(G_SHIFT_PAGE_BYTE - S_SHIFT_SECTOR_BYTE))-(s_curr_n_byte >> 9))
02210                            )
02211                        );
02212    
02213    Disable_interrupt();  
02214    for(i=0;i<512;i++)
02215    {
02216       *ram=Nf_rd_byte();
02217       ram++;
02218    }
02219    Enable_interrupt();  
02220    nf_xfer_update_vars();
02221    Nf_access_signal_off();
02222 
02223 #if (NF_XMCR_MODULE_SHARED == ENABLED)
02224    nf_XMCR_disable();
02225 #endif
02226 
02227    return CTRL_GOOD;   
02228 }
02229 

Generated on Wed Sep 23 09:17:02 2009 for ATMEL by  doxygen 1.5.3