www.pudn.com > SMSC USB2.0.zip > sm.c


/*============================================================================ 
  ____________________________________________________________________________ 
                                ______________________________________________ 
   SSSS  M   M          CCCC          Standard Microsystems Corporation 
  S      MM MM   SSSS  C                    Austin Design Center 
   SSS   M M M  S      C                 11000 N. Mopac Expressway 
      S  M   M   SSS   C                Stonelake Bldg. 6, Suite 500 
  SSSS   M   M      S   CCCC                Austin, Texas 78759 
                SSSS            ______________________________________________ 
  ____________________________________________________________________________ 
  Copyright(C) 1999, Standard Microsystems Corporation 
  All Rights Reserved. 
  This program code listing is proprietary to SMSC and may not be copied, 
  distributed, or used without a license to do so.  Such license may have 
  Limited or Restricted Rights. Please refer to the license for further 
  clarification. 
  ____________________________________________________________________________ 
  Notice: The program contained in this listing is a proprietary trade 
  secret of SMSC, Hauppauge, New York, and is copyrighted 
  under the United States Copyright Act of 1976 as an unpublished work, 
  pursuant to Section 104 and Section 408 of Title XVII of the United 
  States code. Unauthorized copying, adaption, distribution, use, or 
  display is prohibited by this law. 
  ____________________________________________________________________________ 
  Use, duplication, or disclosure by the Government is subject to 
  restrictions as set forth in subparagraph(c)(1)(ii) of the Rights 
  in Technical Data and Computer Software clause at DFARS 52.227-7013. 
  Contractor/Manufacturer is Standard Microsystems Corporation, 
  80 Arkay Drive, Hauppauge, New York, 1178-8847. 
  ____________________________________________________________________________ 
  ____________________________________________________________________________ 
  sm.c - smart media mass storage class implementation file 
  ____________________________________________________________________________ 
  comments tbd 
  ____________________________________________________________________________ 
  Revision History 
  Date      Who  Comment 
  ________  ___  _____________________________________________________________ 
  11/##/01  cds  initial version 
  11/27/01  cds  overrode _lun_enable_mux with fmc code to enable lun data mux 
                 without caller needing to know what specific device is at that 
                 lun. 
  01/##/02  cds  ported smil library.  reads work, writes do not. 
  01/08/02  cds  modified test_unit_ready to simply return "ok", and created 
                 sm_init_controller to initialize smart media-only state 
                 variables 
  01/15/02  cds  - fixed bug in max lba computation.  32 bit value was only 
                   using 16-bit and 8-bit operands and result was being truncated 
                 - adjusted fmc read transfer interaction to only read 1 
                   lba per split until the end of the physical block.  at that 
                   point, the max lba per split is set to be equal to physical 
                   block for all remaining lbas.  (fmc handles sector remainder 
                   in final phyblock) 
  02/26/02  tbh  added NULL placeholder in _fmc_set_callback() invocations 
                 changed strcpy to strncpy for safety 
  04/18/02  cds  - removed hardware ecc calculations during auto read blk_xfers 
                 to help debug read crc errors. 
                 - Added stub code to switch between 
                 multi-block reads, single-block reads and pio single-block reads 
                 - Added mode sense override to be able to correctly report write-protect 
                 status to the host, so that it never even attempts to send a 
                 write command. 
                 - Added fmc_options() and fmc_timeout() to routines using xfer 
                 routines to ensure fmc behaves properly for our device 
                 - Added entry points that allow you to attempt to 'restore' damaged 
                 cards.  by default, these are #if 0'd out. 
  04/24/02  tbh  set sensep to sense_media_change when media becomes known 
  04/28/02  cds  - issued a soft-reset when a zone-change occurs (and possily a 
                 new sector-map built) between write splits. 
  05/16/02  cds  moved k_smart_media_eraser option into sm.h 
  05/24/02  cds  fixed addressing bug when calculating offset of error byte 
                 when a 1-bit error is detected during fmc blk xfer.  Also 
                 created compile-time option to turn error correction code 
                 on or off. 
  05/30/02  cds  turned off auto-xfer in sm_write_end_xfer, before calling write_flush 
                 so that the write_flush could make use of the sram buffers 
                 when doing sector copies. 
  06/03/02  cds  checked for error before turning off auto-xfer bit & doing 
                 copy_flush() in sm_write_end_xfer. 
  06/26/02  cds  fixed a typo in read_end_burst to trap both single-bit error cases 
  06/27/02  cds  removed sm_set_rd_addr() and sm_set_wr_addr(), and replaced 
                 calling code to instead call the virtual media method to 
                 do it. 
  06/29/02  ds   Removed check for write-protection on write commands. 
  07/01/02  tbh  write-protect is now handled at the lun layer, but since SM 
                 uses primordial code to detect wp i put the test back in here 
                 to be safe. 
  07/02/02  cds  separated sm_read_id() command from sm_identify_media flash 
                 configuration detection case statement.  This allows derived 
                 nand.c to get an id-code w/o an interpretation for auto-detection 
                 or for non-smart media codes that may get returned. 
  07/09/02  cds  renamed WorkBuf to g_sector_buffer 
  07/12/02  tbh  lun string name change caued by mandate from on high 
  07/29/02  cds  - removed g_media_err_code references 
                 - protected software ecc calls to only be included if 
                   there is a smart media lun, since the nand code does not 
                   do software ecc 
                 - reduced sm_identify_media_format by detecting parameters, 
                   then copying them into the media structure at the end. 
  07/31/02  cds  called media_set_active(...) instead of setting g_active_media 
                 to select a new media object. 
  08/06/02  cds  added code to "write protect" 256+8 page smart media cards, 
                 so that existing cards can be read, but not written to. 
  08/09/02  cds  - used attribute flag to determine whether to force Smart Media 
                   compatible rw cycle timing for a data xfer. 
                 - separated setting the device address from code that calculates 
                   a the physical address from the mapper's virtual address. 
                 - converted physical address variable into 3 separate xdata bytes 
                   for quick-access when incrementing & writing to the device. 
  08/13/02  cds  added support for a new identify media command that describes a 
                 smart media card with the ability write/erase multiple blocks 
                 simultaneously 
  08/14/02  cds  fixed a bug with write/erase functionality that was caused by 
                 not initializing g_nand_rw_speed... there by sending garbage 
                 commands to the smc. 
  08/20/02  cds  - updated k_trace_hw_sm tracepoints to be more readable 
                 - removed #if/#endif statements from around the hardware ECC (must be used now!) 
                 - re-added a line of code that drops CE after every WRITE split 
                   (need to test if this can be safely removed to improve n2k performance) 
  09/04/02  cds  - address name & usage change-over 
                    g_addr_sector => g_addr_page, 
                    g_addr_page   => g_addr_segment, 
                    _media_data(sectors_per_block)  => _media_data(pages_per_block) 
                    _media_data(cis_phy_block)      => _media_data(boot_block) 
                    _media_data(cis_sector)         => _media_data(boot_sector) 
                    (new item)                      => _media_data(segments_per_page) 
                 - debugging hooks added into new nand_utils.c module 
  09/11/02  cds  added a sm_soft_reset() call in write_begin_first_split, in case 
                 a write begins on the first page of a new zone that needed to be 
                 paged in. 
  09/12/02  tbh  replaced strncpy() with memcpy() to save data space. 
  09/19/02  cds  set default media optimization options to none, and general 
                 codecleaning. 
  09/22/02  cds  set lun_media_process_idle flag after a write to indicate that 
                   cache needs flushing when device goes idle 
                 checks for write-caching on dfa_read 
  10/03/02  cds  - fixed 1-bit ecc code to correctly resume a transfer by turning off 
                   auto-transfer, correcting the bit, transmitting the buffer, waiting 
                   for tx interrupt bit, then re-enabling auto-xfer.  This fixed 
                   code is a bit dangerous, for it waits infinitely for the host 
                   to accept the corrected packet.   
                 - extracted sram bit correction code into a function to conserve 
                   code space 
                 - updated ecc detection code to use ramwr toggle to determine 
                   which buffer has the error bit, instead of trying to detect 
                   it from the isr0 ram wr/rd a/b toggles. 
  10/05/02  cds  - fixed repair card to call nand_util code to repair a smart media 
                   card if the boot block becomes corrupted. 
                   (update)  force book block repair if the k_sm_repair_flag is set, whether 
                             a valid one is found or not. 
  10/14/02  cds  - fixed sm_read_end_burst() to only issue a k_resume if there is more blk xfer to do.                    
  10/15/02  cds  - updated sm_read_end_burst() to return immediately with error in case of double-bit error detected, or 
                   if single-bit error detected in full-speed mode. 
  10/17/02  cds  - project-wide lun data & vtbl paging to reduce code space.            
                 - removed g_active_media from _lun_data, _lun_() virtual functions     
                 - added _lun_data_rd() and _lun_data_wr() macros to bypass lun paging  
                 - added lun_set_active(log_lun) function to switch luns                
  10/29/02  cds  - checked mapper to verify all data pages are valid before staring a split 
                 - added function sm_check_data_status(..) to check range of pages for bad data_status fields. 
                   if any field has less than 4 bits set, it is considered to be 'bad'   
  10/30/02  cds  - worked around hardware glitch that doesn't bother to tell us which buffer contains the 
                   1-bit ecc error it told us about.  The buffer is calculated by comparing the fmc_cnt with  
                   what it was originally.  This only works as long as subsequent xfers are either even in count, or the last one.  
                   (which it happens to for our purposes) 
  10/31/02  cds  - fixed 1-bit ecc error buffer detection by reading the bit BEFORE turning off auto-xfer.  This simplifies the code                    
  11/02/02  cds  - minor tweaks to code that set and cleared bits,  
                 - updated tracepoint categories 
                 - removed remnants of 1-bit ecc buffer determination code.  
  11/13/02  ds   added bit_count fns that are referred to but not compiled in. fixed it.  
  11/13/02  ds   modified sm_wait_rdy_with_timeout to incorporate nand_interleave_media's check for busy signal.               
============================================================================*/ 
#define __sm_dot_c__ 
#include "project.h" 
 
// provide vtable definition '_vtbl_cf' 
code _vtbl_defn(sm) ; 
 
extern xdata uint8 x_sm_redt_data[] ; 
 
 
//----------------------------------------------------------------------------- 
// smart media 'media layer" routines 
//----------------------------------------------------------------------------- 
t_result sm_media_check_format(void)reentrant; 
t_result sm_media_seek_cis(void) reentrant; 
t_result sm_read_cis_sect(uint8 *)reentrant; 
t_result sm_validate_cis(uint8 *) reentrant ; 
t_result sm_media_erase_block(void)reentrant; 
t_result sm_media_erase_card(void)reentrant; 
t_result sm_wait_rdy_with_timeout(uint16 ) reentrant; 
 
 
//----------------------------------------------------------------------------- 
// read fmc xfer callbacks 
//----------------------------------------------------------------------------- 
t_result sm_read_begin_xfer(void) reentrant; 
t_result sm_read_end_xfer(void) reentrant ; 
t_result sm_read_begin_split(void) reentrant; 
t_result sm_read_end_split(void) reentrant ; 
t_result sm_read_end_burst(void) reentrant ; 
 
//----------------------------------------------------------------------------- 
// write fmc xfer callbacks 
//----------------------------------------------------------------------------- 
t_result sm_write_begin_xfer(void) reentrant; 
t_result sm_write_end_xfer(void) reentrant ; 
t_result sm_write_begin_split(void) reentrant; 
t_result sm_write_begin_first_split() reentrant ; 
t_result sm_write_end_split(void) reentrant ; 
t_result sm_write_begin_burst(void) reentrant; 
t_result sm_write_end_burst(void) reentrant ; 
 
 
//------------------------------------------------------------------------- 
//------------------------------------------------------------------------- 
t_result nand_cmd_read_id(void) reentrant; 
t_result nand_cmd_read_id_ex(void) reentrant; 
t_result nand_cmd_check_status(void) reentrant; 
t_result nand_cmd_reset_device(void) reentrant; 
 
 
 
//+------------------------------------------------------------------------ 
// redundant data buffer functions 
//------------------------------------------------------------------------- 
extern xdata uint8  g_sector_buffer[k_sm_sector_sz]  ; 
uint8 bit_count8 ( uint8 ) reentrant ; 
uint8 bit_count16( uint16 ) reentrant ; 
 
 
//+------------------------------------------------------------------------ 
// utility (debug) functions 
//------------------------------------------------------------------------- 
t_result util_blank_smart_media_card(void) reentrant ; 
void util_trace_buffer(uint8* sector, uint16 size) reentrant; 
void util_trace_ms_extra_data() reentrant; 
void util_trace_nand_extra_data() reentrant; 
void util_trace_page() reentrant; 
void util_trace_map_data() reentrant; 
void util_trace_phy_block() reentrant; 
void util_trace_zone() reentrant; 
void util_trace_media() reentrant; 
void util_trace_map_media() reentrant ; 
void util_safe_erase_media() reentrant ; 
void util_trace_log_media() reentrant ; 
void util_create_bad_128mb_media(void) reentrant; 
void util_test_hardware_ecc(uint32 lba, uint16 ix_bit) reentrant; 
void util_create_1bit_error(uint32 lba) reentrant; 
void util_create_2bit_error(uint32 lba) reentrant; 
 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
#define _hdw_clk_domain_bug_workaround() { _nop_(); _nop_(); } 
 
 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
xdata uint8  x_sm_redt_data[k_sm_redt_buffer_sz] ; 
 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
xdata uint16 _sm_log2phy[k_sm_max_zones_per_table*k_sm_max_lb_per_zone]; 
xdata uint8  _sm_assign_map[k_sm_max_zones_per_table*k_sm_max_block_num/8]; 
xdata uint8  _sm_valid_data_map[k_sm_max_zones_per_table*k_sm_max_block_num/8]; 
 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
xdata uint8 g_nand_rw_speed ; 
 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
xdata uint8 g_nand_rd_addr_msb ; 
xdata uint8 g_nand_rd_addr_mid ; 
xdata uint8 g_nand_rd_addr_lsb ; 
xdata uint8 g_nand_wr_addr_msb ; 
xdata uint8 g_nand_wr_addr_mid ; 
xdata uint8 g_nand_wr_addr_lsb ; 
 
 
#ifdef k_trace_hw_smc 
 
// trace functions 
void sm_set_rd_cmd(uint8 cmd) reentrant ; 
void sm_set_wr_cmd(uint8 cmd) reentrant ; 
 
void _sm_set_rd_cmd(uint8 cmd) reentrant 
{ 
  trace1(0, sm, 50, "sm_set_rd_cmd(%02x)", cmd) ; 
  _sm_hw_set_rd_cmd(); 
  _sm_data_wr(cmd); 
  _sm_hw_set_rd_data(g_nand_rw_speed); 
} 
void _sm_set_wr_cmd(uint8 cmd) reentrant 
{ 
  trace1(0, sm, 50, "_sm_set_wr_cmd(%02x)", cmd) ; 
  _sm_hw_set_wr_cmd() ; 
  _sm_data_wr(cmd); 
  _sm_hw_set_wr_data(g_nand_rw_speed); 
} 
 
uint8 _sm_data_rd() reentrant 
{ 
  uint8 val ; 
  val = sm_data ; 
  trace1(0, sm, 50, "sm_data_rd(): %02x", val) ; 
  return (val ); 
} 
 
void _sm_data_wr(uint8 val) reentrant 
{ 
  trace1(0, sm, 50, "sm_data_wr(): %02x", val) ; 
  sm_data=val ; 
} 
 
void _sm_hw_set_rd_data(uint8 msk) reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_wr_data|kbm_enable_wp|msk); 
  trace1(0, sm, 50, "_sm_hw_set_rd_data() - sm_mode_ctl:%02x", (kbm_wr_data|kbm_enable_wp|msk)) ; 
} 
 
void _sm_hw_set_rd_cmd() reentrant 
{ 
  trace1(0, sm, 50, "_sm_hw_set_rd_cmd() - sm_mode_ctl:%02x", (kbm_wr_cmd|kbm_enable_wp)) ; 
  sm_mode_ctl=(uint8)(kbm_wr_cmd| kbm_enable_wp); 
} 
 
void _sm_hw_set_rd_addr() reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_wr_addr|kbm_enable_wp) ; 
  trace1(0, sm, 50, "_sm_hw_set_rd_addr() - sm_mode_ctl:%02x", (kbm_wr_addr|kbm_enable_wp)) ; 
} 
 
void _sm_hw_set_rd_standby() reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_standby|kbm_enable_wp) ; 
  trace1(0, sm, 50, "_sm_hw_set_rd_standby() - sm_mode_ctl:%02x", (kbm_standby|kbm_enable_wp)) ; 
} 
 
void _sm_hw_set_wr_data(uint8 msk) reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_wr_data|kbm_disable_wp|msk); 
  trace1(0, sm, 50, "_sm_hw_set_wr_data() - sm_mode_ctl:%02x", (kbm_wr_data|kbm_disable_wp|msk) ) ; 
} 
 
void _sm_hw_set_wr_cmd() reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_wr_cmd|kbm_disable_wp) ; 
  trace1(0, sm, 50, "_sm_hw_set_wr_cmd() - sm_mode_ctl:%02x", (kbm_wr_cmd|kbm_disable_wp)) ; 
} 
 
void _sm_hw_set_wr_addr() reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_wr_addr|kbm_disable_wp) ; 
  trace1(0, sm, 50, "_sm_hw_set_wr_addr() - sm_mode_ctl:%02x", (kbm_wr_addr|kbm_disable_wp)) ; 
} 
 
void _sm_hw_set_wr_standby() reentrant 
{ 
  sm_mode_ctl=(uint8)(kbm_standby|kbm_disable_wp); 
  trace1(0, sm, 50, "_sm_hw_set_wr_standby() - sm_mode_ctl:%02x", (kbm_standby|kbm_disable_wp)) ; 
} 
 
void _sm_rd_cmd_begin(uint8 cmd) reentrant 
{ 
  trace1(0, sm, 50, "_sm_rd_cmd_begin(%02x).", cmd) ; 
  x_smc_stat = kbm_smc_stat_rdy ; 
  trace1(0, sm, 0, "x_smc_stat = %02x", kbm_smc_stat_rdy) ; 
  sm_set_rd_cmd(cmd); 
} 
 
\void _sm_wr_cmd_begin(uint8 cmd) reentrant 
{ 
  trace1(0, sm, 50, "_sm_wr_cmd_begin(%02x)", cmd) ; 
  x_smc_stat = kbm_smc_stat_rdy ; 
  trace1(0, sm, 0, "x_smc_stat = %02x", kbm_smc_stat_rdy) ; 
  sm_set_wr_cmd(cmd); 
} 
 
t_bool _sm_hw_bsy() reentrant 
{ 
  uint8 val ; 
  val = (!(x_smc_stat & kbm_smc_stat_rdy))?k_true:k_false ; 
  trace1(0, sm, 50, "_sm_hw_bsy? %c", (val?'Y':'N')) ; 
  return (val ); 
} 
#endif 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_dbg_dump_redt_data() 
// 
// Declaration: 
//   void sm_dbg_dump_redt_data(uint8 cmd) reentrant 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_dbg_dump_redt_data() reentrant 
{ 
  uint8 i ; 
 
  for (i=0; i<16;i++) 
  { 
    trace2(0, sm, 0, "x_sm_redt_data[%d]:%02x", i, (uint16) x_sm_redt_data[i]) ; 
  } 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_set_rd_cmd() 
// 
// Declaration: 
//   void sm_set_rd_cmd(uint8 cmd) reentrant 
// 
// Purpose: 
//   set up the media for issuing read command 
//   (using write protection signal to prevent accidental writes) 
// 
// Arguments: 
//   cmd  - command to be issued.  should be one of the following 
//          constants: k_sm_read, k_sm_read_redt, k_sm_read2, k_sm_reset_chip 
//          k_sm_read_status or k_sm_read_id 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_set_rd_cmd(uint8 cmd) reentrant 
{ 
  trace1(0, sm, 50, "sm_set_rd_cmd(%02x)", cmd) ; 
  _sm_hw_set_rd_cmd(); 
  _sm_data_wr(cmd); 
  _sm_hw_set_rd_data(g_nand_rw_speed); 
} 
 
 
 
void sm_set_wr_cmd(uint8 cmd) reentrant 
{ 
  trace1(0, sm, 50, "sm_set_wr_cmd(%02x)", cmd) ; 
  _sm_hw_set_wr_cmd() ; 
  _sm_data_wr(cmd); 
  _sm_hw_set_wr_data(g_nand_rw_speed); 
} 
 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_check_status() 
// 
// Declaration: 
//   t_result sm_check_status(void) 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_check_status(void) reentrant 
{ 
  uint8 status ; 
 
  _sm_set_rd_cmd(k_sm_read_status); 
  status = _sm_data_rd() ; 
  trace1(0, sm, 0, "sm_check_status:  status:%02x", status ) ; 
  if (status&kbm_sm_status_write_failed ) 
    return (k_error ); 
  return (k_success ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   bit_count8() 
// 
// Declaration: 
//   t_result bit_count8(void) reentrant ; 
// 
// Purpose: 
//   Count # of bits in a 8-bit value 
// 
// Arguments: 
//   val  - 8-bit value in which to count bits 
// 
// Return: 
//   0-8, depending on the number of bits set in 'val' 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
uint8 bit_count8(uint8 val) reentrant 
{ 
  uint8 cnt=0; 
  while (val) 
  { 
    cnt+=(uint8)(val &0x01); 
    val >>=1 ; 
  } 
  return (cnt); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   TBD 
// 
// Declaration: 
//   TBD 
// 
// Purpose: 
//   Count # of bits in a 16-bit value 
// 
// Arguments: 
//   val  - 16-bit value in which to count bits 
// 
// Return: 
//   0-16, depending on the number of bits set in 'val' 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
uint8 bit_count16(uint16 val) reentrant 
{ 
  uint8 cnt=0; 
  while (val) 
  { 
    cnt+= (uint8) (val&0x01); 
    val>>=1; 
  } 
  return (cnt); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_wait_rdy_with_timeout() 
// 
// Declaration: 
//   t_result sm_wait_rdy_with_timeout(uint16 ticks) reentrant 
// 
// Purpose: 
// 
// Arguments: 
//   none 
// 
// Return: 
// 
// Notes: 
//   currently, not a dfa 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_wait_rdy_with_timeout(uint16 ticks) reentrant 
{ 
  t_sync sync ; 
 
  trace1(0, sm, 0, "g_active_media %02x ", g_active_media); 
  thread_set_timer( ticks ) ; 
  sync = kbm_sync_none ; 
  while ( !(sync & kbm_sync_timer)) 
  { 
    // $$$ cds -> should patch in the usbrst and abort syncs after sm debug 
    sync = thread_got_sync(kbm_sync_timer) ; 
    _thread_clr_sync(sync) ; 
    if (sync & kbm_sync_usbrst) 
    { 
      trace0(0, sm, 1, "sm_wait_rdy_with_timeout() - error: kbm_sync_usbrst"); 
      return (k_usbreset); 
    } 
    if (sync & kbm_sync_abort) 
    { 
      trace0(0, sm, 1, "sm_wait_rdy_with_timeout() - error: kbm_sync_abort"); 
      return (k_aborted); 
    } 
    if (sync & kbm_sync_timer) 
    { 
      trace0(0, sm, 1, "sm_wait_rdy_with_timeout() - timed out"); 
      return (k_timeout); 
    } 
 
    // the actual unique condition 
    if (g_active_media == k_ix_media_nand_int) 
    { 
      if (!nand_int_hw_bsy()) 
      { 
        return (k_success); 
      } 
    } 
    else 
    { 
      if (!_sm_hw_bsy() ) 
      { 
        return (k_success); 
      } 
    } 
  } 
 
  trace0(0, sm, 0, "sm_wait_rdy_with_timeout() - should not get here!!!") ; 
  return (k_success); 
} 
 
 
 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_media_erase_all() 
// 
// Declaration: 
//   t_result sm_media_erase_all(void) reentrant 
// 
// Purpose: 
//   erase all physical blocks on media card, then 
//   rebuild sector mapping table 
// 
// Arguments: 
//   none 
// 
// Return: 
//   k_success  - on successful completion 
// 
// Notes: 
//   currently, not a dfa 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_reset_device(void) reentrant 
{ 
  // reset the chip 
  trace0(0, sm, 0, "sm_reset_device()") ; 
  _sm_rd_cmd_begin(k_sm_reset_chip) ; 
  sm_wait_rdy_with_timeout(k_sm_busy_reset_timeout) ; 
  _sm_hw_set_rd_standby(); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_read_id() 
// 
// Declaration: 
//   uint8 sm_read_id(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
xdata uint8 nand_id_maker ; 
xdata uint8 nand_id_device ; 
xdata uint8 nand_id_3; 
xdata uint8 nand_id_4; 
xdata uint8 nand_id_5; 
xdata uint8 nand_id_ex_1 ; 
 
uint8 sm_read_id(void) reentrant 
{ 
  uint8 dummy ; 
  uint8 i ; 
 
  nand_cmd_read_id(); 
  nand_id_maker  = _sm_data_rd() ; 
  nand_id_device = _sm_data_rd() ; 
  nand_id_3 = _sm_data_rd() ; 
  nand_id_4 = _sm_data_rd() ; 
  nand_id_5 = _sm_data_rd() ; 
 
  trace1(0, sm, 0, "nand maker :%02X", nand_id_maker); 
  trace1(0, sm, 0, "nand device:%02X", nand_id_device) ; 
  trace1(0, sm, 0, "nand id 3  :%02X", nand_id_3); 
  trace1(0, sm, 0, "nand id 4  :%02X", nand_id_4); 
  trace1(0, sm, 0, "nand id 5  :%02X", nand_id_5); 
 
  // turn off chip enable 
  _sm_hw_set_rd_standby(); 
 
  if (0xa5==nand_id_3) 
  { 
    trace0(0, sm, 0, "card has unique Smart Media ID assignment") ; 
  } 
 
  // auto detect advanced card capabilities 
  nand_id_ex_1=0 ; 
  if (nand_id_4 == 0xc0) 
  { 
    nand_cmd_read_id_ex() ; 
    nand_id_ex_1=_sm_data_rd() ; 
    for (i=1;i<8;i++) 
    { 
      dummy = _sm_data_rd() ; 
      trace2(0, sm, 0, "read_id_ex data[%d]:%02x", i, dummy) ; 
    } 
  } 
  // turn off chip enable 
  _sm_hw_set_rd_standby(); 
  return (nand_id_device ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_identify_media_format() 
// 
// Declaration: 
//   t_result sm_media_erase_all(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_identify_media_format(void) reentrant 
{ 
  uint8 idcode ; 
 
  idcode = sm_read_id() ; 
 
  _media_data(segments_per_page)=1; 
  _media_data(options)=kbm_media_data_opt_none; 
  switch (idcode) 
  { 
    /* 8Mbit (1M) NAND */ 
    case 0x6E: 
    case 0xE8: 
    case 0xEC: 
      trace0(0, sm, 0, "1 MB Flash SmartMedia Device. num_zones:1, phy_blks_per_zone:256, log_blks_per_zone:250, pages_per_blk:16 sectors_per_page:0.5") ; 
      _media_data(num_zones)                    =1; 
      _media_data(physical_blocks_per_zone)     =256; 
      _media_data(logical_blocks_per_zone)      =250; 
      _media_data(logical_blocks_per_boot_zone) =1000; 
      _media_data(pages_per_block)              =8; 
      _lun_data(media) &= ~kbm_sm_media_addr_4cyc ;  // 3 cycle addressing 
      x_media_sts |= kbm_media_sts_sm_256_page ; 
      break; 
 
      /* 16Mbit (2M) NAND */ 
    case 0x64: 
    case 0xEA: 
    case 0xF1:          // $$$$ hack 
      trace0(0, sm, 0, "2 MB Flash SmartMedia Device. num_zones:1, phy_blks_per_zone:512, log_blks_per_zone:500, pages_per_blk:16 sectors_per_page:0.5") ; 
      _media_data(num_zones)                    =1; 
      _media_data(physical_blocks_per_zone)     =512; 
      _media_data(logical_blocks_per_zone)      =500; 
      _media_data(logical_blocks_per_boot_zone) =1000; 
      _media_data(pages_per_block)              =8; 
      x_media_sts |= kbm_media_sts_sm_256_page ; 
      _lun_data(media) &= ~kbm_sm_media_addr_4cyc ;  // 3 cycle addressing 
      break; 
 
      /* 32Mbit (4M) NAND */ 
    case 0x6B: 
    case 0xE3: 
    case 0xE5: 
      trace0(0, sm, 0, "4 MB Flash SmartMedia Device. num_zones:1, phy_blks_per_zone:512, log_blks_per_zone:500, pages_per_blk:16 sectors_per_page:1") ; 
      _media_data(num_zones)                    =1; 
      _media_data(physical_blocks_per_zone)     =512; 
      _media_data(logical_blocks_per_zone)      =500; 
      _media_data(logical_blocks_per_boot_zone) =500; 
      _media_data(pages_per_block)              =16; 
      x_media_sts &= ~kbm_media_sts_sm_256_page ; 
      _lun_data(media) &= ~kbm_sm_media_addr_4cyc ;  // 3 cycle addressing 
      break; 
 
      /* 64Mbit (8M) NAND */ 
    case 0xE6: 
      trace0(0, sm, 0, "8 MB Flash SmartMedia Device. num_zones:1, phy_blks_per_zone:1024, log_blks_per_zone:1000, pages_per_blk:16 sectors_per_page:1") ; 
      _media_data(num_zones)                    =1; 
      _media_data(physical_blocks_per_zone)     =1024; 
      _media_data(logical_blocks_per_zone)      =1000; 
      _media_data(logical_blocks_per_boot_zone) =1000; 
      _media_data(pages_per_block)              =16; 
      x_media_sts &= ~kbm_media_sts_sm_256_page ; 
      _lun_data(media) &= ~kbm_sm_media_addr_4cyc ;  // 3 cycle addressing 
      break; 
 
      /*128Mbit (16M)NAND */ 
    case 0x73: 
      trace0(0, sm, 0, "16 MB Flash SmartMedia Device. num_zones:1, phy_blks_per_zone:1024, log_blks_per_zone:1000, pages_per_blk:32 sectors_per_page:1") ; 
      _media_data(num_zones)                    =1; 
      _media_data(physical_blocks_per_zone)     =1024; 
      _media_data(logical_blocks_per_zone)      =1000; 
      _media_data(logical_blocks_per_boot_zone) =1000; 
      _media_data(pages_per_block)              =32; 
      x_media_sts &= ~kbm_media_sts_sm_256_page ; 
      _lun_data(media) &= ~kbm_sm_media_addr_4cyc ;  // 3 cycle addressing 
      break; 
 
      /*256Mbit (32M)NAND */ 
    case 0x75: 
      trace0(0, sm, 0, "32 MB Flash SmartMedia Device. num_zones:2, phy_blks_per_zone:1024, log_blks_per_zone:1000, pages_per_blk:32 sectors_per_page:1") ; 
      _media_data(num_zones)                    =2; 
      _media_data(physical_blocks_per_zone)     =1024; 
      _media_data(logical_blocks_per_zone)      =1000; 
      _media_data(logical_blocks_per_boot_zone) =1000; 
      _media_data(pages_per_block)              =32; 
      x_media_sts &= ~kbm_media_sts_sm_256_page ; 
      _lun_data(media) &= ~kbm_sm_media_addr_4cyc ;  // 3 cycle addressing 
      break; 
 
      /*512Mbit (64M)NAND */ 
    case 0x76: 
      trace0(0, sm, 0, "64 MB Flash SmartMedia Device. num_zones:4, phy_blks_per_zone:1024, log_blks_per_zone:1000, pages_per_blk:32 sectors_per_page:1") ; 
      _media_data(num_zones)                   =4; 
      _media_data(physical_blocks_per_zone)    =1024; 
      _media_data(logical_blocks_per_zone)     =1000; 
      _media_data(logical_blocks_per_boot_zone)=1000; 
      _media_data(pages_per_block)             =32; 
      x_media_sts &= ~kbm_media_sts_sm_256_page ; 
      _lun_data(media) |= kbm_sm_media_addr_4cyc ;  // 4 cycle addressing 
      break; 
 
      /* 1Gbit(128M)NAND */ 
    case 0x79: 
      trace0(0, sm, 0, "128 MB Flash SmartMedia Device. num_zones:8, phy_blks_per_zone:1024, log_blks_per_zone:1000, pages_per_blk:32 sectors_per_page:1") ; 
      _media_data(num_zones)                   =8; 
      _media_data(physical_blocks_per_zone)    =1024; 
      _media_data(logical_blocks_per_zone)     =1000; 
      _media_data(logical_blocks_per_boot_zone)=1000; 
      _media_data(pages_per_block)             =32; 
      x_media_sts &= ~kbm_media_sts_sm_256_page ;  // 512+16 
      _lun_data(media) |= kbm_sm_media_addr_4cyc ;  // 4 cycle addressing 
      break; 
    default: 
      trace1(0, sm, 0, "Illegal Device ID Code: %02x", idcode) ; 
      return (k_error ); 
  } 
 
  // clear the rw speed to set sm-compatible mode... this needs to move into some sort of 
  // per-instance variable perhaps in _media_data() or something... 
  g_nand_rw_speed=0 ; 
 
  // check for media write protection 
  trace1(0, sm, 0, "media write protected: %c", ((x_media_sts & kbm_media_sts_sm_wp)?'y':'n')) ; 
  // TRACE1(225, sm, 0, "x_media_sts: %02x", x_media_sts) ; 
 
  // write protect if 
  //  - wp bit is detected 
  //  - 256+8 media is inserted 
  if (_mcu_register_rd(x_media_sts)&(kbm_media_sts_sm_wp|kbm_media_sts_sm_256_page)) 
    _lun_data(media) |= kbm_lun_media_wrprot ; 
  else 
    _lun_data(media) &= ~kbm_lun_media_wrprot ; 
 
  return (k_success ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_soft_reset() 
// 
// Declaration: 
//   void sm_soft_reset(void) reentrant 
// 
// Purpose: 
//   send a software reset to the smart media card 
// 
// Arguments: 
//   none 
// 
// Return: 
//   none 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_soft_reset(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_soft_reset()") ; 
  _sm_rd_cmd_begin(k_sm_reset_chip) ; 
  sm_wait_rdy_with_timeout(k_sm_busy_reset_timeout); 
  _sm_rd_cmd_begin(k_sm_read) ; 
  sm_wait_rdy_with_timeout(k_sm_busy_read_timeout); 
  _sm_hw_set_rd_standby(); 
} 
 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_pio_rd_buf() 
// 
// Declaration: 
//   void sm_pio_rd_buf(uint8 *databuf) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_pio_rd_buf(uint8 *databuf) reentrant 
{ 
  uint16 i; 
  i=(x_media_sts&kbm_media_sts_sm_256_page)?0x100:0x200 ; 
  while (i--) 
    *databuf++ =_sm_data_rd(); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_pio_wr_buf() 
// 
// Declaration: 
//   void sm_pio_wr_buf(uint8 *databuf) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_pio_wr_buf(uint8 *databuf) reentrant ; 
void sm_pio_wr_buf(uint8 *databuf) reentrant 
{ 
  uint16 i; 
  i=(x_media_sts&kbm_media_sts_sm_256_page)?0x100:0x200 ; 
  while (i--) 
    _sm_data_wr(*databuf++) ; 
} 
 
 
 
code uint8 _cis_signature[]={ 0x01,0x03,0xD9,0x01,0xFF,0x18,0x02,0xDF,0x01,0x20}; 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_validate_cis() 
// 
// Declaration: 
//   t_result sm_validate_cis(uint8 *buf) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
// extern void fmc_dbg_dump_sector(uint8* sector) reentrant ; 
t_result sm_validate_cis(uint8 *buf) reentrant 
{ 
#if (k_log_lun_sm < k_max_log_lun) 
  t_result result ; 
  trace0(0, sm, 0, "+sm_validate_cis()") ; 
 
  if ( 0 == ((x_sm_redt_data[k_ix_redt_ecc1_0]^x_eccbuf[0])| 
             (x_sm_redt_data[k_ix_redt_ecc1_1]^x_eccbuf[1])| 
             (x_sm_redt_data[k_ix_redt_ecc1_2]^x_eccbuf[2]))) 
  { 
    trace0(0, sm, 0, "no ecc issues... check to see if the data is there") ; 
    result = (memcmp((uint8*)buf, (uint8*)_cis_signature, 10)?k_error:k_success) ; 
    if (k_success != result) 
    { 
      trace0(0, sm, 0, "error reading sector!") ; 
    } 
    else 
    { 
      return (result ); 
    } 
  } 
  else 
  { 
    trace0(0, sm, 0, "redundant ecc data does not match sector ecc.  compute ecc data from data buffer"); 
    if (k_success == ecc_sw_correct(buf,x_sm_redt_data+0x0D,x_eccbuf)) 
    { 
      trace0(0, sm, 0, "ecc computation successful.  check cis signature.") ; 
      return( memcmp((char *)buf,(char *)_cis_signature,10)?k_error : k_success ); 
    } 
  } 
 
  // check backup cis 
  buf+=0x100; 
  if ( 0 == ((x_sm_redt_data[k_ix_redt_ecc2_0]^x_eccbuf[3])| 
             (x_sm_redt_data[k_ix_redt_ecc2_1]^x_eccbuf[4])| 
             (x_sm_redt_data[k_ix_redt_ecc2_2]^x_eccbuf[5]))) 
    return(memcmp((uint8*)buf,(uint8*)_cis_signature,10)?k_error:k_success); 
 
  trace0(0, sm, 0, "ecc error(s) detected.  tring to correct the data") ; 
  if (k_success == ecc_sw_correct(buf,x_sm_redt_data+0x08,x_eccbuf+0x03)) 
  { 
    trace0(0, sm, 0, "SoftwareECC worked.  compare cis tag") ; 
    return(memcmp((uint8 *)buf,(uint8*)_cis_signature,10)?k_error:k_success); 
  } 
  trace0(0, sm, 0, "cis data invalid") ; 
#else 
  trace0(0, sm, 0, "+sm_validate_cis() - software validation disabled") ; 
  buf=buf ;             // keep compiler quiet 
#endif 
 
 
  return (k_error ); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_redt_is_data_valid() 
// 
// Declaration: 
//   t_result sm_redt_is_data_valid(void) reentrant 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_synch_hw_buff_to_redt_buf(void) reentrant 
{ 
  trace0(0, sm_media, 0, "synching smc redt buf w/ x_sm_redt_data") ; 
 
  XBYTE[0x3660]=0xFF; 
  XBYTE[0x3661]=0xFF; 
  XBYTE[0x3662]=0xFF; 
  XBYTE[0x3663]=0xFF; 
  XBYTE[0x3664]=x_sm_redt_data[k_ix_redt_data_status]; 
  XBYTE[0x3665]=x_sm_redt_data[k_ix_redt_block_status]; 
  XBYTE[0x3666]=x_sm_redt_data[k_ix_redt_lba1_hi] ; 
  XBYTE[0x3667]=x_sm_redt_data[k_ix_redt_lba1_lo] ; 
  XBYTE[0x3668]=x_sm_redt_data[k_ix_redt_lba2_hi] ; 
  XBYTE[0x3669]=x_sm_redt_data[k_ix_redt_lba2_lo] ; 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_set_write_mode_extra_data() 
// 
// Declaration: 
// t_result sm_set_write_mode_extra_data(uint8 *buf) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_set_write_mode_extra_data(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_set_write_mode_extra_data()") ; 
  x_smc_stat = kbm_smc_stat_rdy ; 
  _sm_set_rd_cmd(k_sm_reset_chip); 
  sm_wait_rdy_with_timeout(k_sm_busy_reset_timeout); 
  _sm_set_rd_cmd(k_sm_read_redt); 
  sm_wait_rdy_with_timeout(k_sm_busy_read_timeout); 
  _sm_hw_set_rd_standby(); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_redt_mode() 
// 
// Declaration: 
// t_result sm_write_redt_mode(uint8 *buf) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_set_write_mode_page_data(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_set_write_mode_page_data()") ; 
  x_smc_stat = kbm_smc_stat_rdy ; 
  _sm_set_rd_cmd(k_sm_reset_chip); 
  sm_wait_rdy_with_timeout(k_sm_busy_reset_timeout); 
  _sm_set_rd_cmd(k_sm_read); 
  sm_wait_rdy_with_timeout(k_sm_busy_read_timeout); 
  _sm_hw_set_rd_standby(); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_media_check_format() 
// 
// Declaration: 
//   t_result sm_media_check_format(void) reentrant ; 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
//   this is a function 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_media_check_format(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_media_check_format()") ; 
 
  if ( _lun_is_media_known(g_active_lun) ) 
    return(k_success); 
 
  // set to unknown, until we go through this process 
  _lun_data(media) |= kbm_lun_media_unknown ; 
  if ( k_success != sm_identify_media_format() ) 
    return (k_error); 
 
#ifdef k_sm_repair_card 
  trace0(0, sm, 0, "Forcing the repair of a card") ; 
  util_blank_smart_media_card() ; 
 
  if ( k_success != sm_media_seek_cis() ) 
  { 
    trace0(0, sm, 0, "could not find card-info sector... repairing boot block") ; 
    g_addr_zone=0; 
    for (g_addr_rd_phy_blk=0;g_addr_rd_phy_blk<8;g_addr_rd_phy_blk++) 
    { 
      util_trace_phy_block(); 
    } 
 
    util_blank_smart_media_card() ; 
 
    for (g_addr_rd_phy_blk=0;g_addr_rd_phy_blk<8;g_addr_rd_phy_blk++) 
    { 
      util_trace_phy_block(); 
    } 
 
    if ( k_success != sm_media_seek_cis() ) 
    { 
      trace0(0, sm, 0, "*** unable to repair boot block") ; 
      return (k_error); 
    } 
  } 
#else 
  if ( k_success != sm_media_seek_cis()) 
    return (k_error); 
#endif 
 
  _media_data(assign_zone)=0; 
  g_addr_zone=0; 
 
  if ( k_success != map_build_sector_map()) 
    return (k_error ); 
 
  // sm_dump_log_blk(0) ; 
 
  trace0(0, sm, 0, "media identified") ; 
 
  //  hmmmm... this may be redundant... done in identify-media... 
  _lun_data(media) &= ~kbm_lun_media_unknown ; 
  return (k_success); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dfa_sm_read 
// 
// Declaration: 
//   void dfa_sm_read(void) reentrant 
// 
// Purpose: 
//   Read data from sm media 
// 
// Arguments: 
//   None. 
//   Uses _lun_data and g_bot_cbw to get its parameters. 
// 
// Return: 
//   No return value. 
//   However, on exit the DFA's argument pointer is written with a t_csw_status indicating: 
//     k_command_passed - command completed. 
//     k_command_failed - an error occurred. 
// 
// Notes: 
//   This is the start STATE of the dfa_ata_read DFA. 
//   It overrides dfa_lun_read. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_read_begin_xfer() reentrant 
{ 
  trace4(0, sm, 10, "sm_read_begin_xfer() - start:0x%04X%04X count:0x%04X%04X" , _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(_fmc_get_lb_count_32()), _lw(_fmc_get_lb_count_32())); 
  _lun_data(sensep) = &sense_read_error; 
 
  if (k_success != map_lba2addr_rd( _fmc_get_start_lb_32() ) ) 
  { 
    _lun_data(sensep)=&sense_illegal_address ; 
    trace0(0, sm, 0, "error in lba2addr") ; 
    return (k_error ); 
  } 
 
  if (!g_addr_page) 
  { 
    _lun_data(max_lb_per_split) = _min( _media_data(pages_per_block), _fmc_get_lb_count_32()); 
    trace5(0, sm, 10, "-----read begin xfer - zone:%02d phy:0x%04X log:0x%04X page:%02d count:%02d - first in block", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page, _lun_data(max_lb_per_split) ); 
  } 
  else 
  { 
    _lun_data(max_lb_per_split) = _min( _media_data(pages_per_block) - g_addr_page, _fmc_get_lb_count_32()); 
    trace5(0, sm, 10, "-----read begin xfer - zone:%02d phy:0x%04X log:0x%04X page:%02d count:%02d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page, _lun_data(max_lb_per_split)); 
  } 
  _lun_data(max_lb_per_burst) = _lun_data(max_lb_per_split) ; 
  return (k_success ); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_read_end_xfer 
// 
// Declaration: 
//   t_result sm_read_end_xfer(void); 
// 
// Purpose: 
//   Issue the read command to the smart media device. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_read_end_xfer(void) reentrant 
{ 
  trace0(0, sm, 1, "sm_read_end_xfer()") ; 
 
  _sm_hw_set_rd_standby() ; 
 
  if (k_success != _fmc_get_result()) 
    return (k_error); 
  _lun_data(sensep) = &sense_none; 
  return (k_success ); 
} 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_read_begin_next_split 
// 
// Declaration: 
//   t_result sm_read_begin_next_split(void); 
// 
// Purpose: 
//   Issue the read command to subsequent splits after the first. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_read_begin_split(void) reentrant 
{ 
  trace0(0, sm, 1, "sm_read_begin_split()") ; 
 
  if (k_success != map_lba2addr_rd( _fmc_get_start_lb_32() ) ) 
  { 
    _lun_data(sensep)=&sense_illegal_address ; 
    return (k_error ); 
  } 
 
  if (map_log_blk_has_bad_data()) 
  { 
    if (sm_check_data_status(g_addr_page, (uint8) _fmc_get_lb_count_32())) 
    { 
      trace0(0, sm, 0, "read error detected in lba range") ; 
      nand_cmd_reset_device(); 
      return (k_error); 
    } 
    nand_cmd_reset_device(); 
    trace0(0, sm, 0, "read in log blk that has bad data is OK"); 
  } 
  trace4(0, sm, 0, "beginning split - zone:%d phy:%d log:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page) ; 
 
  // convert virtual zone/block/sector into page/offset address 
  nand_rd_va2pa() ; 
  _sm_rd_cmd_begin(k_sm_read) ; 
  _media_set_read_addr() ; 
  if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout)) 
  { 
    trace0(0, sm, 0, "ssfdc_readsect timeout on busy") ; 
    nand_cmd_reset_device(); 
    return (k_error ); 
  } 
 
  // must set these after the wait rdy otherwise, the rdy low->high will force the fmc-high and mask the interrupt 
  // clear ecc bits 
  _mcu_register_wr(x_smc_stat, (kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b|kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b)); 
  // unmask the ecc err bits 
  _mcu_register_clr_bits(x_smc_stat_msk, (kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b|kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b)); 
  // mask in fmc irqs 
  _mcu_register_clr_bits(x_imr0, kbm_isr0_fmc_irq); 
  // enable blk_xfer_ecc 
  _mcu_register_set_bits(sm_mode_ctl, kbm_sm_mode_ecc_blk_xfer_en) ; 
  trace0(0, sm, 0, "ecc on") ; 
 
  // enable ecc error detection 
#if 0 
   
/* 
  mcu_begin_critical_section(); 
  trace1(0, sm, 0, "    smc_stat: %02x", x_smc_stat) ; 
  trace1(0, sm, 0, "smc_stat_msk: %02x", x_smc_stat_msk) ; 
  trace1(0, sm, 0, " sm_mode_ctl: %02x", sm_mode_ctl) ; 
  trace1(0, sm, 0, "        isr0: %02x", x_isr0); 
  trace1(0, sm, 0, "        imr0: %02x", x_imr0); 
  mcu_end_critical_section(); 
*/ 
#endif 
  return (k_success); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_read_end_split 
// 
// Declaration: 
//   t_result sm_read_end_split(void); 
// 
// Purpose: 
//   nothing to do at the beginning of a split 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_read_end_first_split(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_read_end_first_split()") ; 
 
  // go into overdrive 
  trace2(0, sm, 0, "adjusting split/burst size.  before: max_lb_per_split:%d  max_lb_per_burst: %d", _lun_data(max_lb_per_split), _lun_data(max_lb_per_burst)) ; 
 
  _lun_data(max_lb_per_split) = _min(_media_data(pages_per_block), g_n_lb_this_xfer.u32); 
  _lun_data(max_lb_per_burst) = _lun_data(max_lb_per_split) ; 
 
  trace2(0, sm, 0, "adjusting split/burst size.  after:  max_lb_per_split:%d  max_lb_per_burst: %d", _lun_data(max_lb_per_split), _lun_data(max_lb_per_burst)) ; 
 
  // no need to callback here any more 
  _fmc_set_callback(sm_read_begin_xfer, sm_read_end_xfer, 
                    sm_read_begin_split, sm_read_end_split, 
                    fmc_dflt_callback, fmc_dflt_callback, sm_read_end_burst); 
  return (sm_read_end_split() ); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_read_end_split 
// 
// Declaration: 
//   t_result sm_read_end_split(void); 
// 
// Purpose: 
//   nothing to do at the beginning of a split 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_read_end_split(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_read_end_split()") ; 
//  sm_mode_ctl &= ~kbm_sm_mode_ecc_blk_xfer_en; 
//  TRACE0(247, sm, 0, "ecc_blk_xfer_en off") ; 
  _sm_hw_set_rd_standby() ; 
  return (k_success ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_correct_sram_bit 
// 
// Declaration: 
//   t_result sm_correct_sram_bit(void); 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_correct_sram_bit(uint8 buffer, uint16 offset, uint8 ix_bit) reentrant 
{ 
  t_uw16 addr ; 
  uint8  err_byte; 
 
  trace3(0, sm, 0, "sm_correct_sram_bit():  buffer:%c, offset.bit:%d.%d", ((buffer==4)?'a':'b'), offset, ix_bit) ; 
 
  addr.u8.hi = k_pkt_addrhi[buffer] ; 
  addr.u8.lo = k_pkt_addrlo[buffer] ; 
  addr.u16 += offset ; 
 
  trace1(0, sm, 0, "sram byte addr: %04x", addr.u16) ; 
  _mcu_register_wr(x_sram_addr_lo, addr.u8.lo); 
  _mcu_register_wr(x_sram_addr_hi, addr.u8.hi); 
  _hdw_clk_domain_bug_workaround(); 
  err_byte = _mcu_register_rd(x_sram_data) ; 
  err_byte ^= (1 << ix_bit) ; 
  _mcu_register_wr(x_sram_addr_lo, addr.u8.lo); 
  _mcu_register_wr(x_sram_addr_hi, addr.u8.hi); 
  _hdw_clk_domain_bug_workaround(); 
  _mcu_register_wr(x_sram_data, err_byte) ; 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_read_end_burst 
// 
// Declaration: 
//   t_result sm_read_end_burst(void); 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_read_end_burst(void) reentrant 
{ 
  t_result result ; 
  uint8    buffer ; 
  uint8    err_byte; 
//  uint8    isr ; 
 
  trace0(0, sm, 0, "sm_read_end_burst()") ; 
 
  result = k_success ; 
  buffer = 0 ; 
 
  // check blk_err bit to see if there was a correctable error. 
  err_byte = _mcu_register_rd(x_smc_stat) ; 
  trace1(0, sm, 0, "smc_stat:%02x", (_mcu_register_rd(x_smc_stat))) ; 
  if (err_byte&(kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b)) 
  { 
    trace0(0, sm, 0, "smc_stat_ecc_err_d_a/b -> uncorrectable ecc error (2+bits)") ; 
//    sm_media_set_phyblock_failed();//DDD 
    nand_cmd_reset_device(); 
    return (k_error ); 
  } 
  if (err_byte& (kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b)) 
  { 
    trace0(0, sm, 0, "single-bit ecc error detected!") ; 
 
    if (!sie_is_high_speed()) 
    { 
      trace0(0, sm, 0, "cannot correct single-bit errors at full speed.  reporting read error"); 
      nand_cmd_reset_device(); 
      return (k_error); 
    } 
 
    // this needs to be checked before turning auto-xfer off as per e-mail from Ben 
    buffer = (_mcu_register_rd(x_ep2_ctl)&kbm_ep2_ctl_ramwr_tog)?5:4; 
    trace1(0, sm, 0, "ramwr_toggle reports error in buffer %c", (buffer==4?'a':'b')) ; 
 
    // stop xfer and correct the error 
    _mcu_register_clr_bits(x_fmc_ctl, (kbm_fmc_ctl_auto_trans|kbm_fmc_ctl_auto_tog)); 
    trace0(0, sm, 0, "auto transfer OFF") ; 
 
    if (x_smc_stat&kbm_smc_stat_ecc_err_c_a) 
    { 
      trace2(0, sm, 0, "blk xfer interrupted -> correctable 1-bit error addr:%d.%d", ecc_a_add_h, (ecc_a_add_l&0x07)) ; 
      sm_correct_sram_bit(buffer, ecc_a_add_h, (ecc_a_add_l&0x07)); 
      _mcu_register_wr(x_smc_stat,kbm_smc_stat_ecc_err_c_a); 
    } 
    if (x_smc_stat&kbm_smc_stat_ecc_err_c_b) 
    { 
      trace2(0, sm, 0, "blk xfer interrupted -> correctable 1-bit error addr:%d.%d", (((uint16)ecc_b_add_h)+0x100), (ecc_b_add_l&0x07)) ; 
      sm_correct_sram_bit(buffer, (ecc_b_add_h+0x100), (ecc_b_add_l&0x07)) ; 
      _mcu_register_wr(x_smc_stat,kbm_smc_stat_ecc_err_c_b); 
    } 
    // toggle the buffer to be tx'd 
    if (buffer == 4) 
    { 
      _mcu_register_wr(x_ramrdbc_a1, 0x02) ; 
      _mcu_register_wr(x_ramrdbc_a2, 0x00) ; 
      _mcu_register_wr(x_ep2_ctl, kbm_ep2_ctl_rdtog_valid |(_mcu_register_rd(x_ep2_ctl) & ~kbm_ep2_ctl_ramrd_tog)); 
      _hdw_clk_domain_bug_workaround(); 
      while ( !(x_isr0&kbm_isr0_ramrd_a)) 
      { 
        trace0(0, sm, 0, "waiting for buffer to go out...") ; 
      } 
      trace0(0, sm, 0, "buffer tx'd... should see it on the catc") ; 
    } 
    else 
    { 
      _mcu_register_wr(x_ramrdbc_b1, 0x02); 
      _mcu_register_wr(x_ramrdbc_b2, 0x00); 
      _mcu_register_wr(x_ep2_ctl, kbm_ep2_ctl_rdtog_valid |(_mcu_register_rd(x_ep2_ctl) | kbm_ep2_ctl_ramrd_tog)); 
      _hdw_clk_domain_bug_workaround(); 
      while ( !(x_isr0&kbm_isr0_ramrd_b)) 
        ; 
    } 
    // only turn auto xfer back on if there's more to xfer 
    if ( x_fmc_cnt0|x_fmc_cnt1|x_fmc_cnt2|x_fmc_cnt3) 
    { 
      trace0(0, sm, 0, "auto transfer ON") ; 
      _mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans); 
      return (k_resume ); 
    } 
    else 
    { 
      trace0(0, sm, 0, "xfer is done, DON'T resume") ; 
      return (k_success); 
    } 
  } 
  // wait for device 
  if ( k_success == result) 
  { 
    result = sm_wait_rdy_with_timeout(k_sm_busy_read_timeout) ; 
  } 
  if (k_success != result) 
  { 
    nand_cmd_reset_device(); 
    result =  k_error ; 
  } 
  trace0(0, sm, 0, "leaving read data portion") ; 
  return (result ); 
} 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dfa_sm_read 
// 
// Declaration: 
//   void dfa_sm_read(void) reentrant 
// 
// Purpose: 
//   Read data from sm media 
// 
// Arguments: 
//   None. 
//   Uses _lun_data and g_bot_cbw to get its parameters. 
//k 
// Return: 
//   No return value. 
//   However, on exit the DFA's argument pointer is written with a t_csw_status indicating: 
//     k_command_passed - command completed. 
//     k_command_failed - an error occurred. 
// 
// Notes: 
//   This is the start STATE of the dfa_ata_read DFA. 
//   It overrides dfa_lun_read. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_dfa_read(void) reentrant 
{ 
  trace0(0, sm, 0, "dfa_sm_read"); 
  _fmc_set_options(0); 
  _fmc_set_timeout(10000); 
  _fmc_set_callback(sm_read_begin_xfer, sm_read_end_xfer, 
                    sm_read_begin_split, sm_read_end_first_split, 
                    fmc_dflt_callback, fmc_dflt_callback, sm_read_end_burst); 
 
#ifdef k_enable_write_caching 
 
  // catch the cache 
  if (_media_data(options)&kbm_media_data_opt_write_cache) 
    map_write_cache_flush_all() ; 
#endif 
 
  dfa_lun_read(); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dfa_sm_write 
// 
// Declaration: 
//   void dfa_sm_write(void) reentrant 
// 
// Purpose: 
//   Read data from sm media 
// 
// Arguments: 
//   None. 
//   Uses _lun_data and g_bot_cbw to get its parameters. 
// 
// Return: 
//   No return value. 
//   However, on exit the DFA's argument pointer is written with a t_csw_status indicating: 
//     k_command_passed - command completed. 
//     k_command_failed - an error occurred. 
// 
// Notes: 
//   This is the start STATE of the dfa_ata_write DFA. 
//   It overrides dfa_lun_write. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_begin_xfer(void) reentrant; 
t_result sm_write_begin_xfer() reentrant 
{ 
  t_result result ; 
 
  trace4(0, sm, 10, "sm_write_begin_xfer() - start:0x%04X%04X count:0x%04X%04X" , _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(_fmc_get_lb_count_32()), _lw(_fmc_get_lb_count_32())); 
 
  _lun_data(sensep) = &sense_write_error; 
 
  // copy head sectors... 
  result = map_write_begin( _fmc_get_start_lb_32() ) ; 
 
  if (!g_addr_page) 
  { 
    _lun_data(max_lb_per_split) = _min( _media_data(pages_per_block), _fmc_get_lb_count_32()); 
    trace5(0, sm, 10, "-----write begin xfer - zone:%d phy:%d log:%d page:%d count:%d - first in block", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page, _lun_data(max_lb_per_split) ); 
  } 
  else 
  { 
    _lun_data(max_lb_per_split) = _min( _media_data(pages_per_block) - g_addr_page, _fmc_get_lb_count_32()); 
    trace5(0, sm, 10, "-----write begin xfer - zone:%d phy:%d log:%d page:%d count:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page, _lun_data(max_lb_per_split)); 
  } 
  _lun_data(max_lb_per_burst) = 1 ; 
 
  return (result ); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_end_xfer 
// 
// Declaration: 
//   t_result sm_write_end_xfer(void); 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_end_xfer(void) reentrant 
{ 
  t_result result ; 
  trace0(0, sm, 1, "sm_write_end_xfer()") ; 
 
  if (k_success != _fmc_get_result()) 
    return (k_error); 
 
  _mcu_register_clr_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans); 
  trace0(0, fmc, 0, "auto-transfer bit ==> OFF"); 
 
  result=map_write_flush() ; 
  if (_media_data(options)&(kbm_media_data_opt_write_cache|kbm_media_data_opt_erase_cache)) 
  { 
    _lun_data(media)|=kbm_lun_media_process_idle; 
  } 
  _sm_hw_set_wr_standby() ; 
  _sm_hw_set_rd_standby() ; 
  if (k_success == result) 
    _lun_data(sensep) = &sense_none; 
  return (result ); 
} 
 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_begin_split 
// 
// Declaration: 
//   t_result sm_write_begin_split(void); 
// 
// Purpose: 
//   Issue the write command to the smart media device. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_begin_split() reentrant 
{ 
  uint8 zone_before ; 
  trace0(0, sm, 1, "sm_write_begin_split()"); 
  trace1(0, sm, 0, "g_addr_rd_phy_blk: %d", g_addr_rd_phy_blk) ; 
 
  zone_before = g_addr_zone ; 
 
  // if a new physical block, tell the mapper to go git us one. 
  if (k_success != map_lba2addr_rd(_fmc_get_start_lb_32())) 
    return(k_error); 
 
  if (g_addr_zone != zone_before) 
  { 
    // we've crossed a boundry on a split, do a reset 
    trace0(0, sm, 0, "*** trigger ***  issuing a soft reset on zone-change, in case a sector map was paged in") ; 
    sm_set_write_mode_page_data(); 
  } 
 
  if (map_is_addr_first_in_block()) 
  { 
    if (k_success != map_alloc_wr_blk()) 
      return(k_error); 
  } 
 
 
  // convert virtual address zone/block/sector into page/offsets 
  nand_rd_va2pa() ; 
  nand_wr_va2pa() ; 
 
  trace0(0, sm, 0, "ready to begin writing sectors") ; 
  return (k_success); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_begin_first_split 
// 
// Declaration: 
//   t_result sm_write_begin_split(void); 
// 
// Purpose: 
//   Issue the write command to the smart media device. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_begin_first_split() reentrant 
{ 
  trace0(0, sm, 1, "sm_write_begin_first_split()"); 
 
  // make sure we're in the right mode - fixes a bug where 
  // the first burst of the first split of the xfer begins 
  // on a zone that needed to be paged in... 
  sm_set_write_mode_page_data(); 
 
  // compute phy addresses in case this is the first sector 
  nand_wr_va2pa() ; 
  nand_rd_va2pa() ; 
 
  _fmc_set_callback(sm_write_begin_xfer, sm_write_end_xfer, 
                    sm_write_begin_split, sm_write_end_split, 
                    sm_write_begin_burst, fmc_dflt_callback, sm_write_end_burst); 
  return (k_success); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_end_split 
// 
// Declaration: 
//   t_result sm_write_end_split(void); 
// 
// Purpose: 
//   nothing to do at the beginning of a split 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_end_split(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_write_end_split()") ; 
 
  // remove the auto-increment at end_burst. 
  g_addr_page-= 1 ; 
  // see if that finished the phyblock 
  if (map_is_addr_last_in_block()) 
  { 
    if (k_success != map_rebind_log_blk()) 
    { 
      trace0(0, sm, 0, "mapper error updating logical bindings") ; 
      return (k_error ); 
    } 
  } 
  _sm_hw_set_wr_standby(); 
  _sm_hw_set_rd_standby(); 
 
  // do full-block splits to avoid split overhead on every sector. 
  _lun_data(max_lb_per_split) = _media_data(pages_per_block) ; 
  return (k_success ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_begin_burst 
// 
// Declaration: 
//   t_result sm_write_begin_burst(void); 
// 
// Purpose: 
//   Issue the write command to the smart media device. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_begin_burst() reentrant 
{ 
  trace4(0, sm, 0, "+sm_write_begin_burst() - zone:%d WR_PHY:%d log:%d page:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page) ; 
  _sm_set_wr_cmd(k_sm_write_data); 
  _media_set_write_addr() ; 
  _mcu_register_set_bits(sm_mode_ctl, kbm_sm_mode_ecc_blk_xfer_en); 
  _sm_hw_ecc_wr_start() ; 
  _mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy); 
  trace1(0, sm, 0, "smc_mode_ctl: %02x", sm_mode_ctl); 
  trace1(0, sm, 0, "    smc_stat: %02x", x_smc_stat); 
 
  trace0(0, sm, 0, "ready for burst") ; 
  return (k_success); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_write_end_burst 
// 
// Declaration: 
//   t_result sm_write_end_burst(void); 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A t_result indicating: 
//     k_success - command completed. 
// 
// Notes: 
//   This is a FUNCTION, not a DFA. 
//   Do not yeild, or run a DFA, from within this callback. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_write_end_burst(void) reentrant 
{ 
 
  trace0(0, sm, 0, "sm_write_end_burst()") ; 
  _sm_hw_ecc_wr_stop() ; 
  sm_mode_ctl &= ~kbm_sm_mode_ecc_blk_xfer_en; 
  x_smc_stat = kbm_smc_stat_rdy ; 
 
#if 1 
  trace0(0, sm, 0, "cmd:  write") ; 
  _sm_set_wr_cmd(k_sm_write); 
#else 
  if (g_addr_page==(_media_data(pages_per_block)-1)) 
  { 
    trace0(0, sm, 0, "cmd:  write") ; 
    _sm_set_wr_cmd(k_sm_write); 
  } 
  else 
  { 
    trace0(0, sm, 0, "cmd:  write-cache"); 
    _sm_set_wr_cmd(k_nand_cmd_write_cache); 
  } 
#endif 
 
  // increment the addresses during this time of programming 
  g_addr_page++ ; 
  nand_incr_addr() ; 
 
  if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_programming_timeout)) 
  { 
    trace0(0, sm, 0, "error programming flash") ; 
    nand_cmd_reset_device(); 
    g_addr_page-- ; 
    return (k_error ); 
  } 
 
  if (k_success != nand_cmd_check_status()) 
  { 
    trace0(0, sm, 0, "sm_write_end_burst - write fault") ; 
    g_addr_page-- ; 
    return (k_error ); 
  } 
  return (k_success ); 
} 
 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dfa_sm_write 
// 
// Declaration: 
//   void dfa_sm_write(void) reentrant 
// 
// Purpose: 
//   Read data from sm media 
// 
// Arguments: 
//   None. 
//   Uses _lun_data and g_bot_cbw to get its parameters. 
// 
// Return: 
//   No return value. 
//   However, on exit the DFA's argument pointer is written with a t_csw_status indicating: 
//     k_command_passed - command completed. 
//     k_command_failed - an error occurred. 
// 
// Notes: 
//   This is the start STATE of the dfa_ata_write DFA. 
//   It overrides dfa_lun_write. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_dfa_write(void) reentrant 
{ 
  trace0(0, sm, 0, "dfa_sm_write"); 
 
  // check for write protection 
  if ( _sm_is_media_wp() ) 
  { 
    trace0(0, sm, 0, "card is write protected") ; 
    _lun_data(sensep)=&sense_write_protect ; 
    __thread_return_dfa(k_error) ; 
  } 
 
  if (_mcu_register_rd(x_media_sts)&kbm_media_sts_sm_256_page) 
  { 
    trace0(0, sm, 0, "256+8 mode fmdu not implemented") ; 
    __thread_return_dfa(k_error) ; 
  } 
 
  _fmc_set_options(0); 
  _fmc_set_timeout(10000); 
  _fmc_set_callback(sm_write_begin_xfer, sm_write_end_xfer, 
                    sm_write_begin_first_split, sm_write_end_split, 
                    sm_write_begin_burst, fmc_dflt_callback, sm_write_end_burst); 
  dfa_lun_write(); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_power_dn() 
// 
// Declaration: 
//   t_result sm_power_dn() reentrant 
// 
// Purpose: 
//   erase all physical blocks on media card, then 
//   rebuild sector mapping table 
// 
// Arguments: 
//   none 
// 
// Return: 
//   k_success  - on successful completion 
// 
// Notes: 
//   currently, not a dfa 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_power_dn() reentrant 
{ 
  trace0(0, sm, 0, "sm_power_dn()") ; 
  _sm_hw_set_rd_standby(); 
  return (k_success ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_power_up() 
// 
// Declaration: 
//  t_result sm_power_up(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_power_up(void) reentrant 
{ 
  trace0(0, sm, 0, "+sm_power_up()"); 
  return (k_success ); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_reset_controller() 
// 
// Declaration: 
//   void sm_reset_controller(void) reentrant 
// 
// Purpose: 
//   erase all physical blocks on media card, then 
//   rebuild sector mapping table 
// 
// Arguments: 
//   none 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_reset_controller(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_reset_controller()"); 
  trace1(0, sm, 0, " --> _sm_has_media(): %c", (_sm_has_media()?'Y':'N')) ; 
/* 
  if ( _sm_has_media() ) 
  { 
    nand_cmd_reset_device() ; 
  } 
*/ 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dfa_sm_identify_media 
// 
// Declaration: 
//   void dfa_sm_identify_media(void); 
// 
// Purpose: 
//   determine if smart media is present the device and if so, 
//   determine max lba and lb size 
// 
// Arguments: 
//   none 
// 
// Return: 
//   none 
// 
// Notes: 
//   This is a DFA 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void dfa_sm_identify_media(void) reentrant 
{ 
  trace0(0, sm, 1, "dfa_sm_identify_media()"); 
  _lun_data(media) |= kbm_lun_media_unknown ; 
 
 
  if (k_success != sm_media_check_format()) 
  { 
#if 0 
    sm_media_repair_card() ; 
    if ( k_success != sm_media_check_format() ) 
      _thread_return_dfa(k_error) ; 
#else 
    _thread_return_dfa(k_error) ; 
#endif 
  } 
#ifdef k_smart_media_eraser 
  sm_media_erase_card() ; 
#endif 
 
#if 1 
 
  // util_safe_erase_media() ; 
  // util_create_bad_128mb_media() ; 
  // util_trace_map_media() ; 
  // util_trace_log_media() ; 
  // util_test_hardware_ecc(0x62,0); 
  // util_create_2bit_error(0x0000bba2); 
#endif 
 
 
  _lun_data(capacity.lba_max.u32) = (uint32) _media_data(num_zones) * (uint32) _media_data(logical_blocks_per_zone) * (uint32) _media_data(pages_per_block) ; 
  _lun_data(capacity.lba_sz.u32)  = 512 ; 
 
  if ( x_media_sts & kbm_media_sts_sm_256_page ) 
    _lun_data(capacity.lba_max.u32) /= 2 ; 
 
  _lun_data(capacity.lba_max.u32) -= (uint32) 1 ; 
 
  // media is now known 
  _lun_data(media) &= ~kbm_lun_media_unknown; 
  _lun_data(sensep) = &sense_media_change; 
 
  trace2(0, sm, 0, "smart media capacity:  lba_max:%04x%04x lba_sz:00000200", _hw(_lun_data(capacity.lba_max.u32)), _lw(_lun_data(capacity.lba_max.u32))) ; 
 
 
  thread_return_dfa(k_success) ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_init_unit() 
// 
// Declaration: 
//   void sm_init_unit(void) reentrant 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_init_unit(void) reentrant 
{ 
  trace0(0, sm, 1, "sm_init_unit()"); 
 
  // initialize the _lun_data 
  _lun_data(device_type) = k_device_type_sm ; 
 
  // set the hardware to standby-mode 
  _sm_hw_set_rd_standby(); 
 
  thread_return_dfa(k_success) ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   TBD 
// 
// Declaration: 
//   TBD 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   This is a DFA, not a FUNCTION. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void dfa_sm_initialize_media() reentrant 
{ 
  trace0(0, sm, 1, "dfa_sm_initialize_media()"); 
 
  nand_cmd_reset_device() ; 
  _lun_data(media)&=~kbm_lun_media_changed; 
  _thread_return_dfa(k_success); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   TBD 
// 
// Declaration: 
//   TBD 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   This is a DFA, not a FUNCTION. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void dfa_sm_reset_media() reentrant 
{ 
  trace0(0, sm, 0, "dfa_sm_reset_media()"); 
  thread_set_timer(2) ; 
  while (!thread_got_sync(kbm_sync_timer)) ; 
  nand_cmd_reset_device() ; 
  _thread_return_dfa(k_success); 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_initialize_controller() 
// 
// Declaration: 
//   void sm_initialize_controller(void) reentrant 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_initialize_controller(void) reentrant 
{ 
  trace0(0, sm, 0, "sm_initialize_controller()") ; 
 
#ifdef k_smart_media_eraser 
  memcpy(_lun_data(device_id), "SM Eraser", k_lun_max_devid_sz) ; 
#else 
  memcpy(_lun_data(device_id), "SM", k_lun_max_devid_sz) ; 
#endif 
 
  // pre-set error, media & copymode to initial values 
  media_set_active(k_ix_media_sm) ; 
  _media_data(log2phy_map) = (t_log2phy_map_ref) _sm_log2phy; 
  _media_data(assign_map)  = (t_assign_map_ref)  _sm_assign_map; 
} 
 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   sm_dfa_verify() 
// 
// Declaration: 
//   void sm_dfa_verify(void); 
// 
// Purpose: 
//   Verify that the data on the drive matches the data sent down. 
// 
// Arguments: 
//   None. 
//   Uses _lun_data and g_bot_cbw to get its parameters. 
// 
// Return: 
//   No return value. 
//   However, on exit the DFA's argument pointer is written with a t_csw_status indicating: 
//     k_command_passed - command completed. 
//     k_command_failed - an error occurred. 
// 
// Notes: 
//   This is the start STATE of the dfa_ata_verify DFA. 
//   It overrides dfa_lun_verify. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void sm_dfa_verify() reentrant 
{ 
  trace0(0, sm, 0, "dfa_ata_verify"); 
  // _fmc_set_callback(sm_read_begin_xfer, sm_read_end_xfer, sm_read_begin_split, sm_read_end_split, sm_read_begin_burst, fmc_dflt_callback, sm_read_end_burst); 
  dfa_lun_verify(); 
} 
 
//------------------------------------------------------------------------------ 
// Name: 
//  TBD 
// 
// Declaration: 
//  TBD 
// 
// Purpose: 
//  TBD 
// 
// Arguments: 
//  TBD 
// 
// Return: 
//  TBD 
// 
// Notes: 
//  TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result sm_check_data_status(uint8 page, uint8 count) reentrant 
{ 
  uint8 page_save; 
  t_bool bad_block; 
  uint8 data_status; 
 
  trace2(0, sm, 0, "sm_check_data_status(%d, %d) - check to see if physical block contains any pages w/ bad data", page, count) ; 
 
  page_save=g_addr_page; 
  g_addr_page=page; 
 
  nand_rd_va2pa() ; 
  _sm_rd_cmd_begin(k_sm_read_redt) ; 
  _media_set_read_addr() ;  
 
  bad_block=k_false; 
  while (count--) 
  { 
    if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout)) 
    { 
      trace0(0, sm, 0, "**** sm_media_read_extra_data() - timed out trying to read extra data") ; 
      nand_cmd_reset_device() ; 
      return(k_error); 
    } 
    // sm read auto-increments 
    _sm_data_rd();  
    _sm_data_rd();  
    _sm_data_rd();  
    _sm_data_rd();      // reserved 
 
    data_status=_sm_data_rd();  // data status  
    _sm_data_rd();      // block status 
    _sm_data_rd(); 
    _sm_data_rd();      // block addr field 1 
    _sm_data_rd();  
    _sm_data_rd();  
    _sm_data_rd();      // ecc field - 2 
    _sm_data_rd(); 
    _sm_data_rd();      // block addr field 2 
    _sm_data_rd(); 
    _sm_data_rd(); 
    _sm_data_rd();      // ecc field - 1 
 
    if (data_status != 0xff) 
    { 
      if (bit_count8(data_status) < 4) 
      { 
        trace1(0, sm, 0, "detected invalid data status: %02x", data_status); 
        bad_block=k_true; 
        break; 
      } 
    } 
  }            
  g_addr_page=page_save; 
  return (bad_block); 
} 
 
 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
void nand_rd_va2pa() reentrant 
{ 
  uint16 zone; 
  t_udw32 page; 
 
  // compute physical zone from  
  TRACE3(358, nand, 0, "nand_rd_va2pa() g_addr_zone:%d g_addr_rd_phy_blk:%d g_addr_page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_page) ;   
  zone=(uint16)(g_active_media==k_ix_media_sm)?g_addr_zone:(g_addr_zone%g_nand_zones_per_chip) ; 
  page.u32=((uint32)zone* (uint32)_media_data(physical_blocks_per_zone)+ (uint32)g_addr_rd_phy_blk)* (uint32)_media_data(pages_per_block)+ (uint32)g_addr_page ; 
  if (_mcu_register_rd(x_media_sts)&kbm_media_sts_sm_256_page) 
    page.u32<<=1 ; 
   
  g_nand_rd_addr_msb = page.u8.lh; 
  g_nand_rd_addr_mid = page.u8.hl; 
  g_nand_rd_addr_lsb = page.u8.lo;  
} 
 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
void nand_wr_va2pa() reentrant 
{ 
  uint16 zone; 
  t_udw32 page;   
 
  TRACE3(359, nand, 0, "nand_wr_va2pa() g_addr_zone:%d g_addr_wr_phy_blk:%d g_addr_page:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_page) ;   
  zone=(uint16)(g_active_media==k_ix_media_sm)?g_addr_zone:(g_addr_zone%g_nand_zones_per_chip) ; 
  page.u32=((uint32)zone* (uint32)_media_data(physical_blocks_per_zone)+ (uint32)g_addr_wr_phy_blk)* (uint32)_media_data(pages_per_block)+ (uint32)g_addr_page ; 
  if (_mcu_register_rd(x_media_sts)&kbm_media_sts_sm_256_page) 
    page.u32<<=1 ; 
  g_nand_wr_addr_msb = page.u8.lh; 
  g_nand_wr_addr_mid = page.u8.hl; 
  g_nand_wr_addr_lsb = page.u8.lo;  
} 
 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
void nand_incr_addr() reentrant 
{ 
  g_nand_rd_addr_lsb++ ; 
  g_nand_wr_addr_lsb++ ; 
} 
 
//+----------------------------------------------------------------------------- 
//------------------------------------------------------------------------------ 
void nand_select_card( void ) reentrant 
{ 
  uint8 card ; 
  uint8 cs ; 
 
 // #ifdef k_interleave_demo 
 // nand_int_select_chip(g_addr_segment); 
 // return; 
 // #endif 
  // map zone to card/chip 
  card=g_addr_zone/g_nand_zones_per_chip ;  // at least 1 zone per chip 
  ////////////////////////////////////////////////////////// $$$ 
  // calc cs gpio from card.  
  if (_mcu_register_rd(x_chip_id) == 0x18) 
  { 
    cs= 1 << card ; 
  } 
  else 
  { 
    // bit 0-3 are chip selects 4-7, bits 4-7 are cs 0-3, and signals are inverted 
    // i don't know why this was done this way...  
    cs= ~(1<<(card^0x04)); 
  } 
  TRACE2(360, nand, 0, "nand chip select %d, gpiob_out:%02X", card, cs) ; 
  _mcu_register_wr(x_gpiob_out, cs) ;  //for 211 
  ///////////////////////////////////////////////////////// $$$ 
}