nf_mngt.c

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

Generated on Fri Oct 31 14:31:24 2008 for ATMEL by  doxygen 1.5.3