www.pudn.com > SMSC USB2.0.zip > ms.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 - memory stick mass storage class implementation file
____________________________________________________________________________
comments tbd
____________________________________________________________________________
Revision History
Date Who Comment
________ ___ _____________________________________________________________
11/##/01 tbh initial version
02/26/02 tbh changed strcpy to strncpy for safety
04/01/02 tbh read_boot now finds 2 boot blocks on cards that have them
04/02/02 tbh added ms_copy_page
04/17/02 tbh override dfa_lun_mode_sense
04/18/02 tbh removed that override. superclass method handles it now.
05/07/02 cds added a rw_intra_burst callback to actually perform the blk_xfer inner loop
to get around xdata-access bug in the chip
05/09/02 cds added call to _dev_soft_reset() when a usbreset occurs during rw_intra_bursts
06/03/02 cds updated ms_write_end_xfer() to turn off auto-xfer so that
the sector copy can use the fmdu.
06/19/02 tbh converted to read boot into xdata buf instead of packet buf
since bot layer is can now run concurrently with discovery
06/20/02 tbh tweaked the intra-burst callback to stop clearing the isr bit
to be compatible with the perf opto done in fmc_transfer
06/26/02 tbh added nops in ms_wait_msc_stat_sif_with_timeout.
two back to back reads of the alt_stat register causes failure.
there is some latency issue causing intermittant failure...
inserting nops fixes it.
07/01/02 tbh write-protect check is now performed in the lun layer
07/09/02 cds renamed WorkBuf to g_sector_buffer
07/12/02 tbh lun string name change caused by mandate from on high
07/17/02 tbh ms_write_end_xfer sets g_fmc_rslt if map_write_flush returns an error
because fmc_transfer doesn't check the return code of the callback.
I feared breaking all of the other luns by changing fmc...
07/18/02 tbh fixed long standing (but until recently dormant) bug in
ms_rw_intra_burst_callback where && was erroneously used
in place of &.
07/23/02 tbh the ms_wait_msc_stat_sif_with_timeout nop injection was insufficient,
it seems. i increased the number of ops and moved them into the do
loop to delay betwean -every- read of the ms_alt_stat register.
this appears to resolve the issue of the cards formatted by DoTop
becoming unreadable in the 210.
07/31/02 cds called media_set_active(...) instead of setting g_active_media
to select a new media object.
08/06/02 tbh added _force_one_burst_per_split to solve the SanDisk 64MB cards
w/ date codes < J [bug report br308]
08/13/02 tbh added status check after read error in read-begin-burst to
distinguish uncorrectabel error from correctable error on last block.
08/28/02 tbh added extra get-int after block-end command for read and write
to ensure that no error happened issuing that command (shawn's suggestions).
also changed interpretation of uncorrectable error bits from
"all relevant bits set -> uncorrectable error" to
"any relevant bit set -> uncorrectable error" to resolve the
data corruption issue on sony cards (sorry, no bug reporter number
was entered yet)
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)
=> _media_data(segments_per_page)
09/12/02 tbh replaced strncpy() with memcpy() to save data space.
09/18/02 cds initialized _media_data(options) field to kbm_media_data_opts_none
10/17/02 cds updated for new lun vtbl and lun_data macros
11/01/02 tbh made xbuf_rd() visible so ms_media.c can call it.
ms_read_boot_block was using the wrong boot block when more than one
exists. changed to use the lowest-numbered one, per the spec.
move write-protection test to occur before map_build_sector_map
to avoid erroneous block erase on write protected disks.
11/02/02 tbh added ms_is_this_blk_in_bad_blk_tbl().
added ms_find_map_block() to see if any exists, and compare contents.
11/03/02 cds - updated ms_is_this_blk_in_bad_blk_tbl() to include info block
- added new global g_ms_user_area_start_blk to help mapper know which blocks
are to be used for mapping
- updated bad-block table code to read data in big endian format
============================================================================*/
#define __ms_dot_c__
#include "project.h"
#include "dev.h"
code _vtbl_defn(ms);
void fmc_dbg_dump_sector(uint8* sector) reentrant;
//#define k_memory_stick_eraser
//------------------------------------------------------------------------------
// module globals
// status
xdata uint8 _factor;
xdata uint8 _status0;
xdata uint8 _status1;
// extra data registers buffer
xdata uint8 g_ms_extra[4];
// shadow registers
xdata uint8 g_ms_blk_addr_msb;
xdata uint8 g_ms_blk_addr_mid;
xdata uint8 g_ms_blk_addr_lsb;
xdata uint8 g_ms_page;
// logical to physical sector mapping table
//xdata uint16 _ms_map_table[512];
#define k_map_boot_blk 0x8000
#define k_map_initial_err 0xfffd
#define k_map_fatal_err 0xfffe
// total number of blocks on the card
xdata t_uw16 _ms_block_per_card;
// block size - 8k or 16k bytes
xdata t_uw16 _ms_byte_per_block;
// segment size - number of card blocks in a card segment
#define k_phy_block_per_segment 512L
#define k_log_block_per_segment 496L
#define k_log_block_per_boot_segment 494L
// pages per block - a page is analogous to a mass storage class logical block, or disk sector
xdata uint16 _ms_page_per_block;
// tables used by the mapper/pager
#define k_ms_max_zones_per_table 2
xdata uint16 _ms_log2phy[k_ms_max_zones_per_table][k_phy_block_per_segment];
xdata uint8 _ms_assign_map[k_ms_max_zones_per_table][k_phy_block_per_segment/8];
xdata uint16 _ms_bad_blk_tbl[256];
xdata uint16 g_ms_user_area_start_blk;
// br308
// set to false when the boot blocks are read.
// set to true if a block write fails with breq after block-end (i.e., exibits the bug).
// provides the solution for the SanDisk 64MB cards w/ date codes < J
static bit _force_one_burst_per_split;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_bool ms_is_this_blk_in_bad_blk_tbl(uint16 blk) reentrant
{
uint8 i;
for (i=0; i<255; i++)
{
// the zeroth entry in this table is the "information block"
// any non-FFFF blocks in the table that are off the end of the card
// are to be ignored.
if (_ms_bad_blk_tbl[i] == 0xFFFF)
return k_no;
if (_ms_bad_blk_tbl[i] == blk)
{
// this physical block appears in the bad block list
trace1(0, ms_media, 110, "alert: block:%d is in the bad block table!", _ms_bad_blk_tbl[i]);
if (!i)
{
trace0(0, ms_media, 110, " and its the information block!");
}
return k_yes;
}
}
return k_no;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_bool ms_is_this_blk_the_information_block(uint16 blk) reentrant
{
// the zeroth entry in this table is the "information block"
if (_ms_bad_blk_tbl[0] == blk)
{
// this physical block appears in the bad block list
trace1(0, ms_media, 110, "alert: block:%d is in the information block!", blk);
return k_yes;
}
return k_no;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_wait_msc_stat_rdy_with_timeout
//
// Declaration:
// t_result ms_wait_msc_stat_rdy_with_timeout(uint8 ticks);
//
// Purpose:
// Wait for the ready bit in the msc status register to go hi indicating that
// the MS card can accept a TPC.
//
// Arguments:
// ticks - a uint8 representing the timeout period in milliseconds.
//
// Return:
// A t_result indicating:
// k_success - the bit was set, and this routine has cleared it.
// k_usbrst - usb reset signalling was detected while waiting.
// k_aborted - traffic occurred on the control pipe while waiting (probably a mass storage reset).
// k_timeout - timeout limit exceeded.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Clears the ready bit after seeing it get set (to rearm for the next one).
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
xdata uint8 status; //!!! NEED PROPER NAMES IF STICK TO THIS SCHEME (AVOID STKOVF)
xdata t_sync sync;
t_result ms_wait_msc_stat_rdy_with_timeout(uint8 ticks) reentrant;
t_result ms_wait_msc_stat_rdy_with_timeout(uint8 ticks) reentrant
{
//uint8 status;
//t_sync sync;
trace1(0, ms, 1, "ms_wait_msc_stat_rdy_with_timeout(ticks:%d)", ticks);
//_stack_dump();
//_stack_check();
thread_set_timer(ticks+1);
do
{
// clear the interrupt generator in the sony block
//status = _ms_register_rd(ms_alt_stat);
status = _mcu_register_rd(x_msc_stat);
sync = thread_got_sync(kbm_sync_usbrst |kbm_sync_abort |kbm_sync_timer);
_thread_clr_sync(sync);
if (sync & kbm_sync_abort)
{
trace0(0, err, 110, "ms_wait_msc_stat_rdy_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_usbrst)
{
trace0(0, err, 110, "ms_wait_msc_stat_rdy_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_timer)
{
trace0(0, err, 110, "ms_wait_msc_stat_rdy_with_timeout() - error: kbm_sync_timer");
return k_timeout;
}
} while ((status & kbm_msc_stat_rdy) != kbm_msc_stat_rdy);
_mcu_register_wr(x_msc_stat, kbm_msc_stat_rdy);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_wait_msc_stat_sif_with_timeout
//
// Declaration:
// t_result ms_wait_msc_stat_sif_with_timeout(uint8 ticks);
//
// Purpose:
// Wait for the sif bit in the msc alternate status register to go hi indicating
// that the getint command can be issued.
//
// Arguments:
// ticks - a uint8 representing the timeout period in milliseconds.
//
// Return:
// A t_result indicating:
// k_success - the bit was set, and this routine has cleared it.
// k_usbrst - usb reset signalling was detected while waiting.
// k_aborted - traffic occurred on the control pipe while waiting (probably a mass storage reset).
// k_timeout - timeout limit exceeded.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Clears the sif bit after seeing it get set (to rearm for the next one)
// by writing the msc staus register (causing alternate status register to clear also.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_wait_msc_stat_sif_with_timeout(uint8 ticks) reentrant;
t_result ms_wait_msc_stat_sif_with_timeout(uint8 ticks) reentrant
{
//uint8 status;
//t_sync sync;
trace1(0, ms, 0, "ms_wait_msc_stat_sif_with_timeout(ticks:%d)", ticks);
//_stack_check();
thread_set_timer(ticks+1);
do
{
// two back to back reads of the alt_stat register appears to cause failure.
// apparently there is some latency issue causing intermittant failure...
// note well that i have not yet invested the time to determine if this
// is really cause by a synchronization issue or not. i merely opted
// for the 'bit ricochet' gambit and inserted a delay between every read of the
// ms_alt_status register. emperical evidence suggests that this fixs the problem...
// but i am not willing to assert that as a proof...
// the actual cause of death could not be determined from the forensic evidence.
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
// clear the interrupt generator in the sony block
status = _ms_register_rd(ms_alt_stat);
//status = _mcu_register_rd(x_msc_stat);
trace1(0, ms, 0, "status:0x%02X", status);
sync = thread_got_sync(kbm_sync_usbrst |kbm_sync_abort |kbm_sync_timer);
_thread_clr_sync(sync);
if (sync & kbm_sync_abort)
{
trace0(0, err, 110, "ms_wait_msc_stat_sif_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_usbrst)
{
trace0(0, err, 110, "ms_wait_msc_stat_sif_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_timer)
{
trace0(0, err, 110, "ms_wait_msc_stat_sif_with_timeout() - error: kbm_sync_timer");
return k_timeout;
}
} while ((status & kbm_msc_stat_sif) != kbm_msc_stat_sif);
_mcu_register_wr(x_msc_stat, kbm_msc_stat_sif);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_wait_fifo_with_timeout
//
// Declaration:
// t_result ms_wait_fifo_with_timeout(uint8 msk, uint8 val, uint8 ticks);
//
// Purpose:
// Wait for the a bit patern in the msc fifo status register to go hi indicating
// that the fifo has emptied, filled, etc. (Waiting for status & mask == value.)
//
// Arguments:
// msk - a uint8 bitmask to be logically and-ed with the msc fifo status register.
// val - a uint8 indicating the desired bit pattern.
// ticks - a uint8 representing the timeout period in milliseconds.
//
// Return:
// A t_result indicating:
// k_success - status & mask == value.
// k_usbrst - usb reset signalling was detected while waiting.
// k_aborted - traffic occurred on the control pipe while waiting (probably a mass storage reset).
// k_timeout - timeout limit exceeded.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_wait_fifo_with_timeout(uint8 msk, uint8 val, uint8 ticks) reentrant;
t_result ms_wait_fifo_with_timeout(uint8 msk, uint8 val, uint8 ticks) reentrant
{
//uint8 status;
//t_sync sync;
trace3(0, ms, 1, "ms_wait_fifo_with_timeout(mask:%02X val:%02X ticks:%d)", msk, val, ticks);
//_stack_check();
thread_set_timer(ticks+1);
do
{
status = _ms_register_rd(ms_fifo_stat);
sync = thread_got_sync(kbm_sync_usbrst |kbm_sync_abort |kbm_sync_timer);
_thread_clr_sync(sync);
if (sync & kbm_sync_abort)
{
trace0(0, err, 110, "ms_wait_fifo_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_usbrst)
{
trace0(0, err, 110, "ms_wait_fifo_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_timer)
{
trace0(0, err, 110, "ms_wait_fifo_with_timeout() - error: kbm_sync_timer");
return k_timeout;
}
} while ((status & msk) != val);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_set_tpc
//
// Declaration:
// t_result ms_set_tpc(uint8 tpc, uint8 count);
//
// Purpose:
// Send a transfer protocol command (TPC) to the MS card.
//
// Arguments:
// tpc - a uint8 indicating the tpc.
// count - a uint8 indicating the number of bytes to move during this command.
//
// Return:
// A t_result indicating:
// k_success - tpc issued.
// k_error - failed to issue tpc.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_set_tpc(uint8 tpc, uint8 count) reentrant;
t_result ms_set_tpc(uint8 tpc, uint8 count) reentrant
{
// profile:
// during read:
// ms_set_tpc 48usec to 76usec
// wait rdy bit 46usec to 74usec
//_profile_on(5);
trace2(0, ms, 0, "ms_set_tpc() tpc:%02X count:%02X", tpc, count);
//_stack_check();
// wait for the rdy bit in msc_stat to go hi
//_profile_on(4);
if (k_success != ms_wait_msc_stat_rdy_with_timeout(10))
return k_error;
//_profile_off(4);
// write the byte count
_ms_register_wr(ms_bc, count);
// write the tpc
_ms_register_wr(ms_tpc_cmd, tpc);
//_profile_off(5);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_get_int
//
// Declaration:
// t_result ms_get_int(uint8 ticks);
//
// Purpose:
// Issue a getint command to solicit the result of the previous command.
//
// Arguments:
// ticks - a uint8 representing the timeout period in milliseconds.
//
// Return:
// A t_result indicating:
// k_success - the module global variable _factor contains the results.
// k_error - either cannot issue the command or read back the results.
// contents of _factor undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
// The module global variable _factor is written with the results as a side effect.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_get_int(uint8 ticks) reentrant;
t_result ms_get_int(uint8 ticks) reentrant
{
// profile:
// during read:
// ms_get_int 108 to 133usec
// wait sif 52usec
// ms_set_tpc 52usec to 76usec
// wait fifo empty 2usec
//_profile_on(6);
trace0(0, ms, 0, "ms_get_int()");
//_stack_check();
// if you dont have this in here sisoft sandra fails. tbh...
// the problem may well be a stack overflow...
#if 1
//_profile_on(6);
// new - dont wait if its already there
if ((_ms_register_rd(ms_alt_stat) & kbm_msc_stat_sif) == kbm_msc_stat_sif)
{_mcu_register_wr(x_msc_stat, kbm_msc_stat_sif);}
else
// end of new
#endif
if (k_success != ms_wait_msc_stat_sif_with_timeout(ticks))
return k_error;
//_profile_off(6);
// write the tpc
//_profile_on(5);
ms_set_tpc(k_ms_tpc_get_int, 1);
//_profile_off(5);
//_profile_on(4);
// wait rx fifo not empty
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
//_profile_off(4);
// read the interrupt data
_factor = _ms_register_rd(ms_rx_db_lsb);
g_tmp = _ms_register_rd(ms_rx_db_msb); // throw away
trace1(0, ms, 0, "_factor:%02X", _factor);
//_profile_off(6);
return k_success;
}
// so far i haven't got the acd code to work correctly...
// but since it doesn't improve performance anyhow, there's not much point...
//#define k_use_acd
#ifdef k_use_acd
//+-----------------------------------------------------------------------------
// Name:
// ms_get_int_acd
//
// Declaration:
// t_result ms_get_int_acd(uint8 ticks);
//
// Purpose:
// Issue a getint command to solicit the result of the previous command.
// Only to be used with ACD mode.
// Allows skipping the wait for SIF, and the set-tpc for getint.
// The goal is to use it to slightly improve the read performance.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - the module global variable _factor contains the results.
// k_error - either cannot issue the command or read back the results.
// contents of _factor undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
// The module global variable _factor is written with the results as a side effect.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_get_int_acd(void) reentrant;
t_result ms_get_int_acd(void) reentrant
{
trace0(0, ms, 0, "ms_get_int_acd()");
//_stack_check();
// wait rx fifo not empty
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
// read the interrupt data
_factor = _ms_register_rd(ms_rx_db_lsb);
g_tmp = _ms_register_rd(ms_rx_db_msb); // throw away
trace1(0, ms, 0, "_factor:%02X", _factor);
return k_success;
}
#endif
//+-----------------------------------------------------------------------------
// Name:
// ms_set_cmd
//
// Declaration:
// t_result ms_set_cmd(uint8 cmd);
//
// Purpose:
// Send a flash command to the MS card.
//
// Arguments:
// cmd - a uint8 representing the command id.
//
// Return:
// A t_result indicating:
// k_success - command issued.
// k_error - failed to issue command.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_set_cmd(uint8 cmd) reentrant;
t_result ms_set_cmd(uint8 cmd) reentrant
{
trace1(0, ms, 0, "ms_set_cmd() cmd:%02X", cmd);
//_stack_check();
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_set_cmd, 1))
return k_error;
// write the command
_ms_register_wr(ms_tx_db_msb, 0);
_ms_register_wr(ms_tx_db_lsb, cmd);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_set_read_reg_addrs
//
// Declaration:
// t_result ms_set_read_reg_addrs(uint8 start, uint8 count);
//
// Purpose:
// Tell the MS card that its registers are to be read by specifying the starting
// register offset and the number of registers to be read.
//
// Arguments:
// start - the offset of the first register to read.
// count - the number of consecutive registers to read.
//
// Return:
// A t_result indicating:
// k_success - read register start/count are delivered to the card.
// k_error - failed to configure the card for a register read.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_set_read_reg_addrs(uint8 start, uint8 count) reentrant;
t_result ms_set_read_reg_addrs(uint8 start, uint8 count) reentrant
{
trace2(0, ms, 0, "ms_set_read_reg_addrs() start:0x%02X count:0x%02X", start, count);
//_stack_check();
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_set_rw_reg, 4))
return k_error;
// write the command
_ms_register_wr(ms_tx_db_msb, count);
_ms_register_wr(ms_tx_db_lsb, start);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, 0);
_ms_register_wr(ms_tx_db_lsb, k_ms_parm_system);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_set_write_reg_addrs
//
// Declaration:
// t_result ms_set_write_reg_addrs(uint8 start, uint8 count);
//
// Purpose:
// Tell the MS card that its registers are to be written by specifying the starting
// register offset and the number of registers to be written.
//
// Arguments:
// start - the offset of the first register to write.
// count - the number of consecutive registers to write.
//
// Return:
// A t_result indicating:
// k_success - write register start/count are delivered to the card.
// k_error - failed to configure the card for a register write.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_set_write_reg_addrs(uint8 start, uint8 count) reentrant;
t_result ms_set_write_reg_addrs(uint8 start, uint8 count) reentrant
{
//_profile_on(6);
trace2(0, ms, 0, "ms_set_write_reg_addrs() start:%02X count:0x%02X", start, count);
//_stack_check();
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_set_rw_reg, 4))
return k_error;
// write the command
_ms_register_wr(ms_tx_db_msb, k_ms_ext_ovwr_flg);
_ms_register_wr(ms_tx_db_lsb, 0);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, count);
_ms_register_wr(ms_tx_db_lsb, start);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
//_profile_off(6);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_read_status
//
// Declaration:
// t_result ms_read_status(void);
//
// Purpose:
// After an error read the status registers to determine the cause.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - the module global variables _status0 and _status1 contain the status.
// k_error - failed to obtain the status.
// contents of _status0 and _status1 undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
// The module global variables _status0 and _status1are written with the results
// as a side effect.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_read_status() reentrant
{
trace0(0, ms, 0, "ms_read_status()");
//_stack_check();
// set the address
if (k_success != ms_set_read_reg_addrs(k_ms_reg_status0, 2))
return k_error;
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_rd_reg, 2))
return k_error;
// read the value
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
_status0 = _ms_register_rd(ms_rx_db_lsb);
_status1 = _ms_register_rd(ms_rx_db_msb);
trace2(0, ms, 110, "_status0:%02X _status1:%02X", _status0, _status1);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_write_parm_reg
//
// Declaration:
// t_result ms_write_parm_reg(uint8 sys_parm, uint8 cmd_parm);
//
// Purpose:
// Write the parameter registers of the MS card in preparation for issuing a
// flash command.
//
// Arguments:
// sys_parm - specific to the flash command about to be issued.
// cmd_parm - specific to the flash command about to be issued.
//
// The following global variables are accessed and delivered to the MS card:
// g_ms_blk_addr_msb
// g_ms_blk_addr_mid
// g_ms_blk_addr_lsb
// g_ms_page
//
// Return:
// A t_result indicating:
// k_success - parameter registers are written.
// k_error - failed write parameter registers. actual contents unknown.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_write_parm_reg(uint8 sys_parm,
uint8 cmd_parm) reentrant;
t_result ms_write_parm_reg(uint8 sys_parm,
uint8 cmd_parm) reentrant
{
trace0(0, ms, 0, "ms_write_parm_reg()");
//_stack_check();
trace3(0, ms, 0, " mwpr - addr:0x00%02X%02X%02X", g_ms_blk_addr_msb, g_ms_blk_addr_mid, g_ms_blk_addr_lsb);
trace3(0, ms, 0, " mwpr - page:0x%02X sys_parm:0x%02X cmd_parm:0x%02X", g_ms_page, sys_parm, cmd_parm);
if (k_success != ms_set_write_reg_addrs(k_ms_parm_system, 6))
return k_error;
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_wr_reg, 6))
return k_error;
// write the parm regs
_ms_register_wr(ms_tx_db_msb, g_ms_blk_addr_msb);
_ms_register_wr(ms_tx_db_lsb, sys_parm);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, g_ms_blk_addr_lsb);
_ms_register_wr(ms_tx_db_lsb, g_ms_blk_addr_mid);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, g_ms_page);
_ms_register_wr(ms_tx_db_lsb, cmd_parm);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_read_extra_data_reg
//
// Declaration:
// t_result ms_read_extra_data_reg(void);
//
// Purpose:
// Read the extra data registers of the active block of the MS card into
// the global variable g_ms_extra. This is the lowest level, after the command
// has been issued. (Several command handlers must access the extra data).
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - the global variable g_ms_extra contains the results.
// k_error - cannot obtain the extra data.
// contents of g_ms_extra undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_read_extra_data_reg(void) reentrant;
t_result ms_read_extra_data_reg() reentrant
{
trace0(0, ms, 0, "ms_read_extra_data_reg()");
//_stack_check();
// set the address
if (k_success != ms_set_read_reg_addrs(k_ms_ext_ovwr_flg, 4))
return k_error;
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_rd_reg, 4))
return k_error;
// read the value
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
g_ms_extra[0] = _ms_register_rd(ms_rx_db_lsb);
g_ms_extra[1] = _ms_register_rd(ms_rx_db_msb);
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
g_ms_extra[2] = _ms_register_rd(ms_rx_db_lsb);
g_ms_extra[3] = _ms_register_rd(ms_rx_db_msb);
trace4(0, ms, 0, "rd xtra[0..3]:%02X%02X%02X%02X", g_ms_extra[0], g_ms_extra[1], g_ms_extra[2], g_ms_extra[3]);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_read_extra_data
//
// Declaration:
// t_result ms_read_extra_data(void);
//
// Purpose:
// Read the extra data registers of the active block of the MS card into
// the global variable g_ms_extra.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - the global variable g_ms_extra contains the results.
// k_error - cannot obtain the extra data.
// contents of g_ms_extra undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_read_extra_data() reentrant
{
trace4(0, ms, 0, "ms_read_extra_data(addr:0x00%02X%02X%02X page:%d)", g_ms_blk_addr_msb, g_ms_blk_addr_mid, g_ms_blk_addr_lsb, g_ms_page);
//_stack_check();
if (k_success != ms_write_parm_reg(0x80, 0x40))
return k_error;
if (k_success != ms_set_cmd(k_ms_block_read))
return k_error;
if (k_success != ms_get_int(5))
return k_error;
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (ms_read_extra_data)");
return k_error;
}
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 110, "error: ced not set (ms_read_extra_data)");
return k_error;
}
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 110, "error: err (ms_read_extra_data)");
if (k_success != ms_read_status())
return k_error;
// if ((_status1 & (kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg)) ==
// (kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg))
if (_status1 & (kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg))
{
trace0(0, err, 110, "error: ucex|ucfg - uncorrectable flash read error (ms_read_extra_data)");
//ms_media_set_phyblock_failed();
return k_error;
}
}
// read the extra data registers
if (k_success != ms_read_extra_data_reg())
return k_error;
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_read_page_data
//
// Declaration:
// t_result ms_read_page_data(uint8 pnr);
//
// Purpose:
// Read a page (512 byte disk sector) from the MS card via pio and store the data
// into either a packet buffer or an xdata buffer. (Lowest level, callable from
// multple command handlers, as necessary.)
//
// Arguments:
// pnr - the packet buffer number. any value greater than or equal to k_max_pnr
// will cause the data to be stored into xdata at _media_data(sector_buffer).
//
// Return:
// A t_result indicating:
// k_success - data read and stored.
// k_error - cannot read data.
// contents of target buffer undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_read_page_data(uint8 pnr) reentrant;
t_result ms_read_page_data(uint8 pnr) reentrant
{
uint16 i;
trace1(0, ms, 0, "ms_read_page_data(pnr:%d)", pnr);
//_stack_check();
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_rd_page_data |0x02, 0))
return k_error;
// read the data
if (pnr < k_max_pnr)
{
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[pnr]);
_mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[pnr]);
// there are always 256 words of device data
#if 1 // opt for improved code density over execution speed since only called on insertion
for (i=0; i<256; i++)
{
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
x_sram_data = _ms_register_rd(ms_rx_db_lsb);
x_sram_data = _ms_register_rd(ms_rx_db_msb);
}
#else // unrolled loop is a little faster, but eats more code space
for (i=0; i<64; i++)
{
if (!_ms_rx_data_fifo_is_full())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_f, ms_fifo_stat_r_buf_f, 10))
return k_error;
x_sram_data = _ms_register_rd(ms_rx_db_lsb);
x_sram_data = _ms_register_rd(ms_rx_db_msb);
x_sram_data = _ms_register_rd(ms_rx_db_lsb);
x_sram_data = _ms_register_rd(ms_rx_db_msb);
x_sram_data = _ms_register_rd(ms_rx_db_lsb);
x_sram_data = _ms_register_rd(ms_rx_db_msb);
x_sram_data = _ms_register_rd(ms_rx_db_lsb);
x_sram_data = _ms_register_rd(ms_rx_db_msb);
}
#endif
}
else
{
uint8 xdata* bufp = _media_data(sector_buffer);
// there are always 256 words of device data
#if 1 // opt for improved code density over execution speed since only called on insertion
for (i=0; i<256; i++)
{
if (_ms_rx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, 0, 3))
return k_error;
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
}
#else // unrolled loop is a little faster, but eats more code space
#if 0
for (i=0; i<64; i++)
{
if (!_ms_rx_data_fifo_is_full())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_f, ms_fifo_stat_r_buf_f, 10))
return k_error;
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
}
#else // unroll it more
for (i=0; i<32; i++)
{
if (!_ms_rx_data_fifo_is_full())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_f, ms_fifo_stat_r_buf_f, 10))
return k_error;
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
*bufp++ = _ms_register_rd(ms_rx_db_lsb);
*bufp++ = _ms_register_rd(ms_rx_db_msb);
}
#endif
#endif
}
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_pio_read_page
//
// Declaration:
// t_result ms_pio_read_page(uint8 pnr);
//
// Purpose:
// Read a page (512 byte disk sector) from the MS card via pio and store the data
// into either a packet buffer or an xdata buffer.
//
// Arguments:
// pnr - the packet buffer number. any value greater than or equal to k_max_pnr
// will cause the data to be stored into xdata at _media_data(sector_buffer).
//
// Return:
// A t_result indicating:
// k_success - data read and stored.
// k_error - cannot read data.
// contents of target buffer undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_pio_read_page(uint8 pnr) reentrant
{
trace1(0, ms, 0, "ms_pio_read_page():%d", g_ms_page);
//_stack_check();
if (k_success != ms_write_parm_reg(0x80, 0x20))
return k_error;
if (k_success != ms_set_cmd(k_ms_block_read))
return k_error;
if (k_success != ms_get_int(5))
return k_error;
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (ms_pio_read_page)");
return k_error;
}
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 110, "error: ced not set (ms_pio_read_page)");
return k_error;
}
if (_factor & kbm_ms_reg_int_breq)
{
trace0(0, ms, 110, "breq (ms_pio_read_page)");
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 110, "error: err (ms_pio_read_page)");
if (k_success != ms_read_status())
return k_error;
// if ((_status1 & (kbm_ms_reg_status1_ucdt |kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg)) ==
// (kbm_ms_reg_status1_ucdt |kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg))
if (_status1 & (kbm_ms_reg_status1_ucdt |kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg))
{
trace0(0, err, 110, "error: ucdt&ucex&ucfg - uncorrectable flash read error (ms_pio_read_page)");
ms_media_set_phyblock_failed();
return k_error;
}
}
if (k_success != ms_read_extra_data_reg())
return k_error;
if (k_success != ms_read_page_data(pnr))
return k_error;
return k_success;
}
trace0(0, err, 110, "error: unrecognized interrupt factor (ms_pio_read_page)");
return k_error;
}
//------------------------------------------------------------------------------
// Name:
// ms_write_all_reg
//
// Declaration:
// t_result ms_write_all_reg(uint8 sys_parm, uint8 cmd_parm);
//
// Purpose:
// Write the all of the of the MS card in preparation for issuing a
// write flash command. Writes the address, sys_parm, cmd_parm, page,
// and extra data.
//
// Arguments:
// sys_parm - specific to the flash command about to be issued.
// cmd_parm - specific to the flash command about to be issued.
//
// The following global variables are accessed and delivered to the MS card:
// g_ms_blk_addr_msb
// g_ms_blk_addr_mid
// g_ms_blk_addr_lsb
// g_ms_page
// g_ms_extra
//
// Return:
// A t_result indicating:
// k_success - parameter registers are written.
// k_error - failed write parameter registers. actual contents unknown.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_write_all_reg(uint8 sys_parm,
uint8 cmd_parm) reentrant;
t_result ms_write_all_reg(uint8 sys_parm,
uint8 cmd_parm) reentrant
{
trace0(0, ms, 0, "ms_write_all_reg()");
//_stack_check();
trace3(0, ms, 10, " addr:0x00%02X%02X%02X", g_ms_blk_addr_msb, g_ms_blk_addr_mid, g_ms_blk_addr_lsb);
trace3(0, ms, 10, " page:0x%02X sys_parm:0x%02X cmd_parm:0x%02X", g_ms_page, sys_parm, cmd_parm);
if (k_success != ms_set_write_reg_addrs(k_ms_parm_system, 10))
return k_error;
// write the tpc
if (k_success != ms_set_tpc(k_ms_tpc_wr_reg, 10))
return k_error;
// write the parm regs
_ms_register_wr(ms_tx_db_msb, g_ms_blk_addr_msb);
_ms_register_wr(ms_tx_db_lsb, sys_parm);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, g_ms_blk_addr_lsb);
_ms_register_wr(ms_tx_db_lsb, g_ms_blk_addr_mid);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, g_ms_page);
_ms_register_wr(ms_tx_db_lsb, cmd_parm);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
// write the extra data
trace4(0, ms, 10, "wr xtra[0..3]:%02X%02X%02X%02X", g_ms_extra[0], g_ms_extra[1], g_ms_extra[2], g_ms_extra[3]);
_ms_register_wr(ms_tx_db_msb, g_ms_extra[1]);
_ms_register_wr(ms_tx_db_lsb, g_ms_extra[0]);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
_ms_register_wr(ms_tx_db_msb, g_ms_extra[3]);
_ms_register_wr(ms_tx_db_lsb, g_ms_extra[2]);
if (!_ms_tx_data_fifo_is_empty())
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
return k_error;
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_write_extra_data
//
// Declaration:
// t_result ms_write_extra_data(void);
//
// Purpose:
// Write the extra data registers of the active block of the MS card from
// the global variable g_ms_extra.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - contents of the global variable g_ms_extra written to card.
// k_error - cannot write the extra data.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_write_extra_data(void) reentrant;
t_result ms_write_extra_data() reentrant
{
trace4(0, ms, 0, "ms_write_extra_data(addr:0x00%02X%02X%02X page:%d)", g_ms_blk_addr_msb, g_ms_blk_addr_mid, g_ms_blk_addr_lsb, g_ms_page);
//_stack_check();
if (k_success != ms_write_all_reg(0x80, 0x40))
return k_error;
if (k_success != ms_set_cmd(k_ms_block_write))
return k_error;
if (k_success != ms_get_int(10))
return k_error;
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (ms_write_extra_data)");
return k_error;
}
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 110, "error: ced not set (ms_write_extra_data)");
return k_error;
}
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 110, "error: !ced&err (ms_write_extra_data)");
return k_error;
}
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_erase_block
//
// Declaration:
// t_result ms_erase_block(void);
//
// Purpose:
// Erase he active block in the MS card.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - block is erased.
// k_error - cannot erase block. contents undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_erase_block() reentrant
{
//_profile_on(7);
trace0(0, ms, 80, "ms_erase_block()");
//_stack_check();
//_profile_on(6);
if (k_success != ms_write_parm_reg(0x80, 0x00))
return k_error;
//_profile_off(6);
//_profile_on(5);
if (k_success != ms_set_cmd(k_ms_block_erase))
return k_error;
//_profile_off(5);
//_profile_on(4);
if (k_success != ms_get_int(100))
return k_error;
//_profile_off(4);
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (ms_erase_block)");
return k_error;
}
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 110, "error: ced not set (ms_erase_block)");
return k_error;
}
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 110, "error: err (ms_erase_block)");
return k_error;
}
//_profile_off(7);
return k_success;
}
//------------------------------------------------------------------------------
// steal a buffer from media.c temporarily (its ok, media.c only uses it for copy-sector).
// actually now that copy sector is done via fmc its probably not used for that purpose
// on the other luns anymore either.
//------------------------------------------------------------------------------
extern xdata uint8 g_sector_buffer[];
void xbuf_rd(uint16 offset, uint16 len, t_memory_ref bufp) reentrant
{
t_xdata_ref srcbufp;
mcu_begin_critical_section();
trace0(0, hal, 0, "mmu_rd()");
srcbufp = g_sector_buffer; // shouldnt this be _media_data(sector_buffer) ???
srcbufp += offset;
for (; len; len--, *bufp++=*srcbufp++);
mcu_end_critical_section();
}
//+-----------------------------------------------------------------------------
// Name:
// ms_read_boot_block
//
// Declaration:
// t_result ms_read_boot_block(void);
//
// Purpose:
// Determine the parameters (capacity etc) of the card by examining the contents
// of the boot block. Configures the _media_data() settings for the media based
// of the contents of the boot block.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - boot block read, _media_data() configured.
// k_error - cannot read boot block. contents of _media_data() undefined.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Boot Block Format:
// page 0: header (368 bytes)
// system entry (48 bytes)
// boot and attribute info (96 bytes)
// page 1: disabled block data
// page 2: card info struct (256 byets)
// identification info (256 bytes)
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ms_read_boot_block(void) reentrant;
t_result ms_read_boot_block() reentrant
{
uint8 blk;
//uint8 pnr;
uint8 boot_count;
t_result rslt;
trace0(0, ms, 80, "ms_read_boot_block()");
_force_one_burst_per_split = k_no; // br308
//_stack_check();
//pnr = mmu_allocate();
// no media/mapper optimizations at this time
_media_data(options) = kbm_media_data_opt_none;
_media_data(sector_buffer) = g_sector_buffer; // sneakily share media.c's buffer
boot_count = 0;
_media_data(boot_block) = 0xFF;
for (blk=0; blk<11; blk++)
{
trace1(0, ms, 80, "checking block %d", blk);
// read page 0 of the block
g_ms_blk_addr_msb = 0;
g_ms_blk_addr_mid = 0;
g_ms_blk_addr_lsb = blk;
g_ms_page = 0;
if (k_success != (rslt = ms_pio_read_page(k_max_pnr)))
{
trace0(0, err, 80, "error: cant read page zero of this block");
continue;
//goto exit;
}
// block status must be set; e.g., 'ok'
if (!(g_ms_extra[k_ovwr_flg_offset] & kbm_ms_ext_ovwr_bkst))
{
trace2(0, ms, 80, "blk:%d bkst:%02X", blk, g_ms_extra[k_ovwr_flg_offset] & kbm_ms_ext_ovwr_bkst);
continue;
}
// system bit must be clear; e.g., 'boot'
if (g_ms_extra[k_mgmt_flg_offset] & kbm_ms_ext_mgmt_sysflg)
{
trace2(0, ms, 80, "blk:%d sysflg:%02X", blk, g_ms_extra[k_mgmt_flg_offset] & kbm_ms_ext_mgmt_sysflg);
continue;
}
// top word of page 0 must be 0x0001
xbuf_rd(0, 2, (uint8*)&g_wtmp);
if (0x0001 != g_wtmp)
{
trace2(0, ms, 80, "blk:%d top word:%04X", blk, g_wtmp);
//dbg_dumpram(k_pkt_addrlo[pnr], k_pkt_addrhi[pnr], 512);
continue;
}
// found the boot block
boot_count++;
trace1(0, ms, 80, "BOOT BLOCK:%d", blk);
if (_media_data(boot_block) == 0xFF)
{
// if more than one boot block is found then choose the lowest numbered
trace0(0, ms, 80, "INSTALLING BOOT BLOCK INTO TABLE");
_media_data(boot_block) = blk;
}
trace1(0, ms, 80, "BOOT AREA MAX BLK NOW:%d", blk);
g_ms_user_area_start_blk=blk+1;
trace0(0, ms, 80, "PAGE 0 (HEADER)");
// block size?
xbuf_rd(418, 1, &(_ms_byte_per_block.u8.hi));
xbuf_rd(419, 1, &(_ms_byte_per_block.u8.lo));
_ms_byte_per_block.u16 *= 1024;
trace1(0, ms, 80, "_ms_byte_per_block:%d", _ms_byte_per_block.u16);
// number of blocks?
xbuf_rd(420, 1, &(_ms_block_per_card.u8.hi));
xbuf_rd(421, 1, &(_ms_block_per_card.u8.lo));
trace1(0, ms, 80, "_ms_block_per_card:%d", _ms_block_per_card.u16);
_media_data(num_zones) = _ms_block_per_card.u16 / k_phy_block_per_segment;
trace1(0, ms, 80, "_ms_zone_per_card:%d", _media_data(num_zones));
_media_data(physical_blocks_per_zone) = k_phy_block_per_segment;
_media_data(logical_blocks_per_zone) = k_log_block_per_segment;
_media_data(logical_blocks_per_boot_zone) = k_log_block_per_boot_segment;
// pages per block?
_ms_page_per_block = _ms_byte_per_block.u16 / 512;
trace1(0, ms, 80, "_ms_page_per_block:%d", _ms_page_per_block);
_media_data(pages_per_block) = _ms_page_per_block;
// 1 segment (sector) per page
_media_data(segments_per_page) = 1 ;
// ASSEMBLER:
// SanDisk 01 (sampled 15 cards)
// Lexar 02, 03 (sampled 15 cards)
// Sony 01 (sampled 4 cards)
// Apacer 01 (sampled 1 card)
#if 0
{
uint8 assembler;
t_udw32 assembly;
xbuf_rd(440, 1, &(assembler));
trace1(0, ms, 80, "assembler code:%d", assembler);
xbuf_rd(441, 80, &(assembly.u8.lh));
xbuf_rd(442, 80, &(assembly.u8.hl));
xbuf_rd(443, 80, &(assembly.u8.lo));
trace3(0, ms, 80, "assembly model code:00%02X%02X%02X", assembly.u8.lh, assembly.u8.hl, assembly.u8.lo);
}
#endif
// this block is only enabled to facilitate debugging the SanDisk 64MB issue...
#if 1 // this is currently unused by the mapper
// found the disabled block data
g_ms_page = 1;
if (k_success != (rslt = ms_pio_read_page(k_max_pnr)))
{
trace0(0, err, 80, "error: cant read page one of this boot block");
continue;
//goto exit;
}
trace0(0, ms, 80, "PAGE 1 (DISABLED BLOCK DATA)");
{
t_uw16 x;
uint8 i;
for (i=0; i<255; i++)
{
#if 0
xbuf_rd(i*2, 1, &x.u8.lo); // big endian
xbuf_rd(i*2+1, 1, &x.u8.hi);
#else
xbuf_rd(i*2, 1, &x.u8.hi); // big endian
xbuf_rd(i*2+1, 1, &x.u8.lo);
#endif
// stop at the end of the list
_ms_bad_blk_tbl[i] = x.u16;
if (x.u16 == 0xFFFF)
break;
if (i)
{
trace1(0, ms, 80, "bad block:%d", x.u16);
}
else
{
trace1(0, ms, 80, "information block:%d", x.u16);
}
trace2(0, ms, 80, " (zone:%d phy:%d)", x.u16/k_phy_block_per_segment, x.u16%512);
if (x.u16/k_phy_block_per_segment > _media_data(num_zones))
{
trace0(0, ms, 80, " (off the end of the card - meaningless)");
continue;
}
g_ms_blk_addr_msb = 0;
g_ms_blk_addr_mid = 0;
g_ms_blk_addr_lsb = x.u16;
g_ms_page = 0;
if (k_success != ms_read_extra_data_reg())
{
trace0(0, err, 80, " error: can't read xtra data");
}
else
{
trace4(0, ms, 80, " xtra[0..3]:%02X%02X%02X%02X", g_ms_extra[0], g_ms_extra[1], g_ms_extra[2], g_ms_extra[3]);
// block status of 0 is bad
if (!(g_ms_extra[k_ovwr_flg_offset] & kbm_ms_ext_ovwr_bkst))
{
trace0(0, ms, 80, " bad block by bkst - mapper will detect");
}
else
{
// if this is seen for VALID bad blocks then ms_media_is_phyblock_ok
// needs to refer to the bad block table before rendering its decision
trace0(0, ms, 80, " good block by bkst - mapper needs assist to detect");
}
}
}
//fmc_dbg_dump_sector((uint8*)_ms_bad_blk_tbl);
}
g_ms_blk_addr_msb = 0;
g_ms_blk_addr_mid = 0;
g_ms_blk_addr_lsb = blk;
#endif
// found the cis/idi page
g_ms_page = 2;
if (k_success != (rslt = ms_pio_read_page(k_max_pnr)))
{
trace0(0, err, 80, "error: cant read page two of this boot block");
continue;
//goto exit;
}
trace0(0, ms, 80, "PAGE 2 (CIS/IDI)");
#if 0 // this is debug stuff
//dbg_dumpram(k_pkt_addrlo[pnr], k_pkt_addrhi[pnr], 512);
{
t_uw16 x, y;
trace0(0, ms, 0, "=====STUFF FROM THE IDI=====");
xbuf_rd(258, 1, &x.u8.lo);
xbuf_rd(259, 1, &x.u8.hi);
trace1(0, ms, 80, "cylinders per head:%d", x.u16);
xbuf_rd(262, 1, &x.u8.lo);
xbuf_rd(263, 1, &x.u8.hi);
trace1(0, ms, 80, "heads per disk:%d", x.u16);
xbuf_rd(264, 1, &x.u8.lo);
xbuf_rd(265, 1, &x.u8.hi);
trace1(0, ms, 80, "bytes per track:%d", x.u16);
xbuf_rd(266, 1, &x.u8.lo);
xbuf_rd(267, 1, &x.u8.hi);
trace1(0, ms, 80, "bytes per sector:%d", x.u16);
xbuf_rd(268, 1, &x.u8.lo);
xbuf_rd(269, 1, &x.u8.hi);
trace1(0, ms, 80, "sectors per track:%d", x.u16);
xbuf_rd(364, 1, &x.u8.lo);
xbuf_rd(365, 1, &x.u8.hi);
trace1(0, ms, 80, "current cylinders per head:%d", x.u16);
xbuf_rd(366, 1, &x.u8.lo);
xbuf_rd(367, 1, &x.u8.hi);
trace1(0, ms, 80, "current heads per disk:%d", x.u16);
xbuf_rd(368, 1, &x.u8.lo);
xbuf_rd(369, 1, &x.u8.hi);
trace1(0, ms, 80, "sectors per track:%d", x.u16);
xbuf_rd(264, 1, &x.u8.lo);
xbuf_rd(265, 1, &x.u8.hi);
xbuf_rd(264, 1, &y.u8.lo);
xbuf_rd(265, 1, &y.u8.hi);
trace2(0, ms, 80, "current capacity in sectors:0x%04X%04X", x.u16, y.u16);
}
#endif
#if 0
// firmware version
{
t_udw32 fwlo;
t_udw32 fwhi;
xbuf_rd(302, 1, &(fwhi.u8.hi));
xbuf_rd(303, 1, &(fwhi.u8.lh));
xbuf_rd(304, 1, &(fwhi.u8.hl));
xbuf_rd(305, 1, &(fwhi.u8.lo));
xbuf_rd(306, 1, &(fwlo.u8.hi));
xbuf_rd(307, 1, &(fwlo.u8.lh));
xbuf_rd(308, 1, &(fwlo.u8.hl));
xbuf_rd(309, 1, &(fwlo.u8.lo));
trace4(0, ms, 80, "fwver:%02X%02X%02X%02X", fwhi.u8.hi, fwhi.u8.lh, fwhi.u8.hl, fwhi.u8.lo);
trace4(0, ms, 80, " %02X%02X%02X%02X", fwlo.u8.hi, fwlo.u8.lh, fwlo.u8.hl, fwlo.u8.lo);
}
#endif
// total logical sectors?
xbuf_rd(270, 1, &(_lun_data(capacity).lba_max.u8.lh));
xbuf_rd(271, 1, &(_lun_data(capacity).lba_max.u8.hi));
xbuf_rd(272, 1, &(_lun_data(capacity).lba_max.u8.lo));
xbuf_rd(273, 1, &(_lun_data(capacity).lba_max.u8.hl));
_lun_data(capacity).lba_max.u32 -= 1;
trace2(0, ms, 80, "Total User-addressable Sectors: %04X%04X", _hw(_lun_data(capacity).lba_max.u32), _lw(_lun_data(capacity).lba_max.u32));
_lun_data(capacity).lba_sz.u32 = 512;
}
//get_out:
rslt = k_error;
if (boot_count)
{
g_addr_zone = 0;
rslt = k_success;
}
//exit:
trace1(0, ms, 80, "found %d boot blocks", boot_count);
trace1(0, ms, 80, "user area starts at block %d", g_ms_user_area_start_blk);
return rslt;
}
//------------------------------------------------------------------------------
t_result ms_find_map_block(void) reentrant;
t_result ms_find_map_block() reentrant
{
uint16 blk;
uint8 zone;
uint8 old_zone;
t_result rslt;
trace0(0, ms, 80, "ms_find_map_block()");
trace1(0, ms, 80, "current zone:%d", g_addr_zone);
rslt = k_error;
zone = _media_data(num_zones) - 1;
old_zone = g_addr_zone;
g_addr_zone = zone;
set_rd_phyblk();
g_ms_page = 0;
for (blk=0; blk<512; blk++)
{
trace2(0, ms, 80, "checking block %d of zone:%d", blk, zone);
// read page 0 of the block
if (k_success != (rslt = ms_pio_read_page(k_max_pnr)))
{
trace1(0, err, 80, "error: cant read page zero of block:%d", blk);
continue;
}
// is it the log2phy map table block? if yes it should get whacked.
if (g_ms_extra[k_mgmt_flg_offset] & kbm_ms_ext_mgmt_atflg)
{
continue;
}
// found the map block
trace0(0, ms_media, 110, "alert: ms_media_is_phyblock_ok() - table block found");
trace1(0, ms, 80, "atflg:%02X", g_ms_extra[k_mgmt_flg_offset] & kbm_ms_ext_mgmt_atflg);
trace1(0, ms, 80, "MAP BLOCK:%d", blk);
fmc_dbg_dump_sector((uint8*)g_sector_buffer);
rslt = k_success;
}
g_addr_zone = old_zone;
trace1(0, ms, 80, "restored zone:%d", g_addr_zone);
return rslt;
}
//+-----------------------------------------------------------------------------
// Name:
// ms_reset_controller
//
// Declaration:
// void ms_reset_controller(void);
//
// Purpose:
// Reset the MSC block of the 210.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void ms_reset_controller() reentrant
{
uint8 loop;
trace0(0, ms, 0, "ms_reset_controller()");
//_stack_check();
ms_mode_ctl |= kbm_ms_mode_ctl_msc_rst;
loop = 0xff;
while (loop--);
ms_mode_ctl &= ~kbm_ms_mode_ctl_msc_rst;
_mcu_register_set_bits(x_fmc_clk_ctl, k_fmc_clk_ctl_ms_20mhz);
_ms_register_set_bits(ms_mode_ctl, kbm_ms_mode_ctl_sien);
}
//+-----------------------------------------------------------------------------
// Name:
// ms_initialize_controller
//
// Declaration:
// void ms_initialize_controller(void);
//
// Purpose:
// Initialize the MSC block of the 210.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void ms_initialize_controller() reentrant
{
trace0(0, ms, 1, "ms_initialize_controller()");
//_stack_check();
//strncpy(_lun_data(k_lun_ms, device_id), "MEMORY STICK", k_lun_max_devid_sz);
memcpy(_lun_data(device_id), "MS", k_lun_max_devid_sz);
_lun_data(device_type) = k_device_type_ms;
_lun_data(max_lb_per_burst) = 1;
_mcu_register_set_bits(x_fmc_clk_ctl, k_fmc_clk_ctl_ms_20mhz);
_ms_register_set_bits(ms_mode_ctl, kbm_ms_mode_ctl_sien);
media_set_active(k_ix_media_ms);
_media_data(log2phy_map) = (t_log2phy_map_ref)_ms_log2phy;
_media_data(assign_map) = (t_assign_map_ref)_ms_assign_map;
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ms_reset_media
//
// Declaration:
// void dfa_ms_reset_media(void);
//
// Purpose:
// Deliver a reset command to the MS card.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// This is a DFA, not a FUNCTION.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_ms_reset_media() reentrant
{
trace0(0, ms, 0, "dfa_ms_reset_media()");
//_stack_check();
// must wait at least 1 msec after por before issuing commands to ms
thread_set_timer(2);
while (!thread_got_sync(kbm_sync_timer));
// issue the reset
ms_set_cmd(k_ms_reset);
_thread_return_dfa(k_success);
}
//+-----------------------------------------------------------------------------
// Name:
// ms_initialize_media2
//
// Declaration:
// void ms_initialize_media2(void);
//
// Purpose:
// After the media has received a reset command, and then at least 1msec has
// expired, clear the media changed flag so that the device layer will not reast
// and initialize the card an more and will instead attempt to identify the media.
//
// Arguments:
// None
//
// 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 a state in a DFA, not a FUNCTION.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void ms_initialize_media2(void) reentrant;
void ms_initialize_media2() reentrant
{
trace0(0, ms, 1, "ms_initialize_media2()");
//_stack_check();
_lun_data(media) &= ~kbm_lun_media_changed;
// house keeping
_thread_return_dfa(k_success);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ms_initialize_media
//
// Declaration:
// void dfa_ms_initialize_media(void);
//
// Purpose:
// After the media has received a reset command wait at least 1msec.
//
// Arguments:
// None
//
// 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 entry state of a DFA, not a FUNCTION.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_ms_initialize_media() reentrant
{
trace0(0, ms, 1, "dfa_ms_initialize_media()");
//_stack_check();
// wait at least 1 millisecond before accessing the device
thread_set_timer(2);
thread_yield_ex(kbm_sync_none, kbm_sync_timer, ms_initialize_media2);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ms_identify_media
//
// Declaration:
// void dfa_ms_identify_media(void);
//
// Purpose:
// Determine the geometry of the MS card that has just been inserted, reset,
// and initialized. Also checks the write rotect status of the card.
//
// Arguments:
// None.
//
// 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 entry state of a DFA, not a FUNCTION.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
extern t_result ms_media_erase_card() reentrant;
extern void util_safe_erase_media() reentrant;
void dfa_ms_identify_media() reentrant
{
trace0(0, ms, 1, "dfa_ms_identify_media()");
//_stack_check();
// locate the boot block and extract relevant parameters
if (k_success != ms_read_boot_block())
{
trace0(0, err, 110, "error: boot blocks not found (dfa_ms_identify_media)");
_thread_return_dfa(k_error);
}
// ms_find_map_block();
#ifdef k_memory_stick_eraser
util_safe_erase_media() ;
#endif
// check the write protect status
if (k_success != ms_read_status())
{
trace0(0, err, 110, "warning: read_status failed");
}
if (_status0 & kbm_ms_reg_status0_wp)
{
trace0(0, ms, 10, "write protected");
_lun_data(media) |= kbm_lun_media_wrprot;
}
else
{
trace0(0, ms, 10, "writeable");
_lun_data(media) &= ~kbm_lun_media_wrprot;
}
if (k_success != map_build_sector_map())
{
_thread_return_dfa(k_error);
}
// media is now known
_lun_data(media) &= ~kbm_lun_media_unknown;
_lun_data(sensep) = &sense_media_change;
_thread_return_dfa(k_success);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// the fmc transfer callbacks
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_read_begin_xfer(void) reentrant;
t_result ms_read_begin_split(void) reentrant;
t_result ms_read_begin_burst(void) reentrant;
t_result ms_read_end_burst(void) reentrant;
t_result ms_read_end_split(void) reentrant;
t_result ms_read_end_xfer(void) reentrant;
//#define k_dbg
#ifdef k_dbg
xdata uint8 dbg_split;
xdata uint8 dbg_burst;
#endif
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// profile:
// ms_read_begin_xfer 335usec to 560usec
// mapping 298usec to 522usec
t_result ms_read_begin_xfer() reentrant
{
uint32 split_sz;
//_profile_on(7);
//TRACE0(142, ms, 10, "ms_read_begin_xfer()");
trace4(0, ms, 10, "ms_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()));
//_stack_check();
_lun_data(sensep) = &sense_read_error;
_fmc_set_options(0);
//_profile_on(6);
if (k_success != map_lba2addr_rd(_fmc_get_start_lb_32()))
return k_error;
set_rd_phyblk();
//_profile_off(6);
//if (map_is_addr_first_in_block())
if (!g_addr_page)
split_sz = _min(_ms_page_per_block, _fmc_get_lb_count_32());
else
split_sz = _min(_ms_page_per_block - g_addr_page, _fmc_get_lb_count_32());
_lun_data(max_lb_per_split) = split_sz;
#ifdef k_dbg
dbg_split = 0;
dbg_burst = 0;
#endif
//_profile_off(7);
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_read_begin_first_split(void) reentrant;
t_result ms_read_begin_first_split() reentrant
{
trace0(0, ms, 1, "ms_read_begin_first_split()");
//_stack_check();
// cheat for speed
//_fmc_set_callback(ms_read_begin_xfer, ms_read_end_xfer, ms_read_begin_split, ms_read_end_split, ms_read_begin_burst, NULL, ms_read_end_burst);
g_fmc_begin_split_callback = (t_fmc_callback)(ms_read_begin_split);
//return ms_read_issue_command();
if (k_success != ms_write_parm_reg(0x80, 0x00))
return k_error;
#ifdef k_use_acd
//_mcu_register_wr(x_isr0, kbm_isr0_fmc_irq);
_ms_register_wr(ms_acd_bc, 2);
_ms_register_wr(ms_acd_ctl, kbm_ms_acd_ctl_adc);
#endif
if (k_success != ms_set_cmd(k_ms_block_read))
return k_error;
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// profile:
// ~490usec to ~750usec
// ~298usec to 565usec
// ~131usec
// ~58usec
t_result ms_read_begin_split() reentrant
{
//_profile_on(7);
trace0(0, ms, 1, "ms_read_begin_split()");
//_stack_check();
//_profile_on(6);
if (k_success != map_lba2addr_rd(_fmc_get_start_lb_32()))
return k_error;
set_rd_phyblk();
//_profile_off(6);
//return ms_read_issue_command();
//_profile_on(5);
if (k_success != ms_write_parm_reg(0x80, 0x00))
return k_error;
//_profile_off(5);
#ifdef k_use_acd
//_mcu_register_wr(x_isr0, kbm_isr0_fmc_irq);
_ms_register_wr(ms_acd_bc, 2);
_ms_register_wr(ms_acd_ctl, kbm_ms_acd_ctl_adc);
#endif
//_profile_on(4);
if (k_success != ms_set_cmd(k_ms_block_read))
return k_error;
//_profile_off(4);
//_profile_off(7);
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// profile:
// ms_rd_begin_burst 201usec normal, 235usec w/ block_end
// ms_get_int 133usec
// ms_set_tpc 52usec
// block_end 58usec
t_result ms_read_begin_burst() reentrant
{
//_profile_on(7);
trace0(0, ms, 1, "ms_read_begin_burst()");
#ifdef k_dbg
trace3(0, ms, 1, "ms_read_begin_burst() - split:%d burst:%d page:%d", dbg_split, dbg_burst, g_ms_page);
#endif
//_stack_check();
#ifdef k_use_acd
//while (!_thread_got_sync(kbm_sync_fmc_irq));
//while (!_mcu_register_rd(x_isr0) & kbm_isr0_fmc_irq);
if (k_success != ms_get_int_acd())
return k_error;
#else
//_profile_on(6);
if (k_success != ms_get_int(5))
return k_error;
//_profile_off(6);
#endif
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (ms_read_begin_burst)");
return k_error;
}
if (_factor & (kbm_ms_reg_int_ced |kbm_ms_reg_int_breq |kbm_ms_reg_int_err) ==
(kbm_ms_reg_int_ced |kbm_ms_reg_int_breq |kbm_ms_reg_int_err))
{
trace0(0, err, 110, "alert: ced&breq&err");
if (k_success != ms_read_status())
return k_error;
// if ((_status1 & (kbm_ms_reg_status1_ucdt |kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg)) ==
// (kbm_ms_reg_status1_ucdt |kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg))
if (_status1 & (kbm_ms_reg_status1_ucdt |kbm_ms_reg_status1_ucex |kbm_ms_reg_status1_ucfg))
{
trace0(0, err, 110, "error: ucdt&ucex&ucfg - uncorrectable flash read error (ms_read_begin_burst)");
ms_media_set_phyblock_failed();
return k_error;
}
trace0(0, err, 110, "warning: correctable flash read error (ms_read_begin_burst)");
}
//------------------------------------------------------------------------------
// removed to try and get reads a bit faster... why test for it if all you do is log trace?
//------------------------------------------------------------------------------
//if (_factor & (kbm_ms_reg_int_breq |kbm_ms_reg_int_err) ==
// (kbm_ms_reg_int_breq |kbm_ms_reg_int_err))
//{
// trace0(0, err, 0, "warning: correctable flash read error");
//}
//------------------------------------------------------------------------------
if (!(_factor & kbm_ms_reg_int_breq))
{
trace0(0, err, 110, "error: breq not set (ms_read_begin_burst)");
return k_error;
}
trace0(0, ms, 0, "breq");
//------------------------------------------------------------------------------
// this does not need to be done for every page even though the flowcharts in the
// ms spec indicate that it does. removing this speeds up reads.
//------------------------------------------------------------------------------
//if (k_success != ms_read_extra_data_reg())
// return k_error;
//------------------------------------------------------------------------------
//TRACE2(329, ms, 0, "n_lb_this_split: %04x%04x" , _hw(g_n_lb_this_split.u32), _lw(g_n_lb_this_split.u32));
if (!(_factor & kbm_ms_reg_int_ced))
{
if (_fmc_get_lb_count_32() == 1L)
{
trace0(0, ms, 110, "issue the block end command");
//_profile_on(5);
if (k_success != ms_set_cmd(k_ms_block_end))
return k_error;
// shawn pointed out to me that there should be a get_int after the block_end
// and no get int after reading the final page. this mod test's that theory.
#if 1
if (k_success != ms_get_int(5))
return k_error;
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 110, "error: missing ced after block end (ms_read_begin_burst)");
return k_error;
}
if (!(_factor & kbm_ms_reg_int_breq))
{
trace0(0, err, 110, "error: missing breq after block end (ms_read_begin_burst)");
return k_error;
}
#endif
//_profile_off(5);
}
}
else
{
trace0(0, ms, 0, "ced");
}
// daken must be set during dma transfers.
// only wr-page-data and rd-page-data can be issued with daken set.
_ms_register_set_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
//_profile_on(5);
if (k_success != ms_set_tpc(k_ms_tpc_rd_page_data |0x02, 0))
{
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
return k_error;
}
//_profile_off(5);
// IMPORTANT! This begin_critical_section() is ended in the 'end_burst' function
// to prevent xdata access while blk_xfer bit is enabled
_mcu_begin_critical_section();
//_profile_off(7);
return k_success;
}
//------------------------------------------------------------------------------
// new ms_intra_burst_callback to prevent access to xdata during a transfer.
// this hack exists only to work around a hardware bug.
// if *any* xdata address is read or written during fmdu xfers to ms
// then the data passing through the fifo will be corrupted.
// this happens often enough during actual usage that it is apparent,
// but is rare enough that it is non obvious.
// a new version of the chip is expected to fix it.
// until then the intra-burst handler ensure no access to xdata until
// the xfer has completed, avoiding the corruption of data by hdw.
// note: xdata access *includes* logging trace... handy, yes?
//------------------------------------------------------------------------------
t_result ms_rw_intra_burst() reentrant
{
// profile: ~200-220usec
//_profile_on(6);
while (1)
{
// poll isr's to check on events that should cause us to break,
// and on those events, set the mask and get out.
if ((_mcu_register_rd(x_isr0) & kbm_isr0_blk_xfer_complete))
{
//irq_control(k_irq_blk_xfer_complete, kbm_irqctl_clear| kbm_irqctl_mask);
// dont clear it here because the irq is no longer used, and the sync is no longer
// delivered, and the fmc layer polls the bit
//_mcu_register_wr(x_isr0, kbm_isr0_blk_xfer_complete);
_mcu_register_set_bits(x_imr0, kbm_isr0_blk_xfer_complete);
//thread_set_sync(g_tid, kbm_sync_fmc_blk);
break;
}
// check for a usb reset during the xfer
else
if (_mcu_register_rd(x_wu_src1) & kbm_wk1_usb_reset)
{
_dev_soft_reset();
thread_set_sync(g_tid, kbm_sync_usbrst);
// you can't get here from there... soft reset puts everything back to por state
break;
}
// abort on status change of memory stick
else
if (_mcu_register_rd(x_wu_src1) & kbm_wk1_crd_sts_chg)
{
if (_mcu_register_rd(x_crd_stat) & kbm_crd_stat_ms_out)
{
_ejected(g_active_lun);
thread_set_sync(g_tid, kbm_sync_abort);
break;
}
}
}
_mcu_end_critical_section();
// always return success and let the fmc_xfer handle error conditions based on the
// synchronizer that was set.
//_profile_off(6);
_profile_off(7);
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_read_end_burst() reentrant
{
// profile: ~3usec
//_profile_on(6);
trace0(0, ms, 99, "ms_read_end_burst()");
#ifdef k_dbg
dbg_burst++;
#endif
//_stack_check();
#if 0
if (!_ms_rx_data_fifo_is_empty())
{
trace0(0, err, 10, "alert - entered read_end_burst before rx fifo emptied - wait before stopping dma");
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_r_buf_e, ms_fifo_stat_r_buf_e, 3)) //rcc test for MS bug tbh!!!
return k_error;
}
#endif
// clear daken before issuing command other than wr-page-data and rd-page-data
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
g_ms_page++;
//_profile_off(6);
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_read_end_split() reentrant
{
// progile: ~20usec
//_profile_on(7);
trace0(0, ms, 99, "ms_read_end_split()");
#ifdef k_dbg
dbg_split++;
#endif
//_stack_check();
// adjust for the next split
_lun_data(max_lb_per_split) = _min(_ms_page_per_block, g_n_lb_this_xfer.u32);
//_profile_off(7);
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// profile: ~7usec
t_result ms_read_end_xfer() reentrant
{
//_profile_on(6);
trace0(0, ms, 99, "ms_read_end_xfer()");
//_stack_check();
// clear daken before issuing command other than wr-page-data and rd-page-data
// need to do this again here in case end burst skiped on error
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
if (k_success != _fmc_get_result())
return k_error;
_lun_data(sensep) = &sense_none;
//_profile_off(6);
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_begin_split(void) reentrant;
t_result ms_write_begin_burst(void) reentrant;
t_result ms_write_end_burst(void) reentrant;
t_result ms_write_end_split(void) reentrant;
t_result ms_write_end_xfer(void) reentrant;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_begin_xfer(void) reentrant;
t_result ms_write_begin_xfer() reentrant
{
uint32 split_sz;
//_profile_on(7);
//TRACE0(162, ms, 1, "ms_write_begin_xfer()");
trace4(0, ms, 10, "ms_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()));
//_stack_check();
_lun_data(sensep) = &sense_write_error;
_fmc_set_options(0);
//_profile_on(6);
if (k_success != map_write_begin(_fmc_get_start_lb_32()))
return k_error;
set_wr_phyblk();
//_profile_off(6);
//if (map_is_addr_first_in_block())
if (!g_addr_page)
{
split_sz = _min(_ms_page_per_block, _fmc_get_lb_count_32());
}
else
{
split_sz = _min(_ms_page_per_block - g_addr_page, _fmc_get_lb_count_32());
}
if (_force_one_burst_per_split) // br308
{
trace0(0, ms, 200, "_force_one_burst_per_split: YES");
_lun_data(max_lb_per_split) = 1;
}
else
{
trace0(0, ms, 200, "_force_one_burst_per_split: NO");
_lun_data(max_lb_per_split) = split_sz;
}
#ifdef k_dbg
dbg_split = 0;
dbg_burst = 0;
#endif
//_profile_off(7);
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_begin_first_split(void) reentrant;
t_result ms_write_begin_first_split() reentrant
{
trace0(0, ms, 10, "ms_write_begin_first_split()");
//_stack_check();
//_fmc_set_callback(NULL, ms_write_end_xfer, ms_write_begin_split, ms_write_end_split, ms_write_begin_burst, NULL, ms_write_end_burst);
g_fmc_begin_split_callback = (t_fmc_callback)(ms_write_begin_split);
//return ms_write_issue_command();
if (k_success != ms_write_all_reg(0x80, _force_one_burst_per_split ? 0x20 : 0x00)) // br308
return k_error;
if (k_success != ms_set_cmd(k_ms_block_write))
return k_error;
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_begin_split() reentrant
{
// profile:
// ms_wr_begin_split 640usec to 820usec to 1.64msec
// mapping 420usec to 620 usec to 1.46msec
// ms_write_all_reg 140usec
// ms_set_cmd 80usec
//_profile_on(7);
trace0(0, ms, 10, "ms_write_begin_split()");
//_stack_check();
//_profile_on(6);
if (k_success != map_lba2addr_rd(_fmc_get_start_lb_32()))
return k_error;
if (map_is_addr_first_in_block())
{
if (k_success != map_alloc_wr_blk())
return k_error;
}
set_wr_phyblk();
//_profile_off(6);
//return ms_write_issue_command();
//_profile_on(5);
if (k_success != ms_write_all_reg(0x80, _force_one_burst_per_split ? 0x20 : 0x00)) // br308
return k_error;
//_profile_off(5);
//_profile_on(4);
if (k_success != ms_set_cmd(k_ms_block_write))
return k_error;
//_profile_off(4);
//_profile_off(7);
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_begin_burst() reentrant
{
_profile_on(7);
trace0(0, ms, 10, "ms_write_begin_burst()");
#ifdef k_dbg
trace3(0, ms, 10, "ms_write_begin_burst() - split:%d burst:%d page:%d", dbg_split, dbg_burst, g_ms_page);
#endif
//_stack_check();
_profile_on(6);
if (k_success != ms_get_int(10))
return k_error;
_profile_off(6);
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (ms_write_begin_burst)");
return k_error;
}
if (_factor & kbm_ms_reg_int_ced)
{
trace0(0, err, 110, "error: ced set before wr-page-data (ms_write_begin_burst)");
return k_error;
}
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 110, "error: ced&err uncorrectable flash write error (ms_write_begin_burst)");
//ms_media_set_phyblock_failed();
return k_error;
}
if (!(_factor & kbm_ms_reg_int_breq))
{
trace0(0, err, 110, "error: breq not set (ms_write_begin_burst)");
return k_error;
}
// daken must be set during dma transfers.
// only wr-page-data and rd-page-data can be issued with daken set.
_ms_register_set_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
_profile_on(5);
if (k_success != ms_set_tpc(k_ms_tpc_wr_page_data |0x02, 0))
{
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
return k_error;
}
_profile_off(5);
// IMPORTANT! This begin_critical_section() is ended in the 'rw_intra_burst' function
// to prevent xdata access while blk_xfer bit is enabled
_mcu_begin_critical_section();
_profile_off(7);
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_end_burst() reentrant
{
//_profile_on(5);
trace0(0, ms, 10, "ms_write_end_burst()");
#ifdef k_dbg
dbg_burst++;
#endif
//_stack_check();
if (!_ms_tx_data_fifo_is_empty())
{
trace0(0, err, 10, "alert - entered write_end_burst before tx fifo emptied - wait before stopping dma");
if (k_success != ms_wait_fifo_with_timeout(ms_fifo_stat_t_buf_e, ms_fifo_stat_t_buf_e, 3))
{
// clear daken before issuing command other than wr-page-data and rd-page-data
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
return k_error;
}
}
// clear daken before issuing command other than wr-page-data and rd-page-data
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
g_ms_page++;
//_profile_off(5);
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_end_split() reentrant
{
//_profile_on(7);
trace0(0, ms, 10, "ms_write_end_split()");
//_stack_check();
#ifdef k_dbg
dbg_split++;
#endif
// NEED get_int for final page of data
// THEN block_end withis its OWN get_int
// shawn pointed out to me that there should be a get_int after the block_end
// and no get int after reading the final page. this mod test's that theory.
#if 0
if (!_force_one_burst_per_split && (g_ms_page < _ms_page_per_block)) // br308
{
trace1(0, ms, 10, "issue the block end command, page:%d", g_ms_page);
//_profile_on(6);
if (k_success != ms_set_cmd(k_ms_block_end))
return k_error;
//_profile_off(6);
}
#else
// get int for the final burst
if (k_success != ms_get_int(10))
return k_error;
_profile_off(6);
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 110, "error: cmdnk (final burst) (ms_write_end_split)");
return k_error;
}
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 110, "error: ced&err uncorrectable flash write error (final burst) (ms_write_end_split)");
//ms_media_set_phyblock_failed();
return k_error;
}
if (!_force_one_burst_per_split && (g_ms_page < _ms_page_per_block)) // br308
{
if (_factor & kbm_ms_reg_int_ced)
{
trace0(0, err, 110, "error: ced set before block end (final burst) (ms_write_end_split)");
return k_error;
}
if (!(_factor & kbm_ms_reg_int_breq))
{
trace0(0, err, 110, "error: breq not set (final burst) (ms_write_end_split)");
return k_error;
}
trace1(0, ms, 10, "issue the block end command, page:%d", g_ms_page);
if (k_success != ms_set_cmd(k_ms_block_end))
return k_error;
if (k_success != ms_get_int(10))
return k_error;
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 110, "error: missing ced after block end (ms_write_end_split)");
return k_error;
}
if (_factor & kbm_ms_reg_int_breq)
{
trace0(0, err, 110, "error: breq set after block-end delivered (ms_write_end_split)");
#if 0
return k_error;
#else
_force_one_burst_per_split = k_yes; // br308
//return k_error;
_ms_pwr_off();
_factor = kbm_ms_reg_int_ced;
_ms_pwr_on();
thread_set_timer(2);
while(!thread_got_sync(kbm_sync_timer));
#endif
}
}
#if 0
// only useful during debugging...
else
{
if (_factor & kbm_ms_reg_int_ced)
{
trace0(0, err, 110, "alert: ced set before block end (final burst) (ms_write_end_split)");
}
if (!(_factor & kbm_ms_reg_int_breq))
{
trace0(0, err, 110, "alert: breq not set (final burst) (ms_write_end_split)");
}
}
#endif
#endif
#if 0
//_profile_on(7);
if (k_success != ms_get_int(10))
return k_error;
//_profile_off(7);
if (_factor & kbm_ms_reg_int_cmdnk)
{
trace0(0, err, 10, "error: cmdnk");
return k_error;
}
if (_factor & kbm_ms_reg_int_breq)
{
//TRACE0(417, err, 0, "alert: breq set after block-end (presumably) delivered");
trace0(0, err, 0, "error: breq set after block-end (presumably) delivered");
_force_one_burst_per_split = k_yes; // br308
//return k_error;
_ms_pwr_off();
_factor = kbm_ms_reg_int_ced;
_ms_pwr_on();
thread_set_timer(2);
while(!thread_got_sync(kbm_sync_timer));
}
if (!(_factor & kbm_ms_reg_int_ced))
{
trace0(0, err, 0, "error: ced not set after block-end delivered");
return k_success;
}
if (_factor & kbm_ms_reg_int_err)
{
trace0(0, err, 10, "error: ced&err uncorrectable flash write error");
//ms_media_set_phyblock_failed();
return k_error;
}
#endif
// see if that finished the phyblock
g_addr_page = g_ms_page - 1;
if (map_is_addr_last_in_block())
{
//_profile_on(5);
if (k_success != map_erase_rd_blk())
{
trace0(0, err, 110, "error: problem erasing rd block (ms_write_end_split)");
return k_error;
}
//_profile_off(5);
//_profile_on(4);
if (k_success != map_bind_wr_blk())
{
trace0(0, err, 110, "error: problem binding wr block (ms_write_end_split)");
return k_error;
}
//_profile_off(4);
}
// adjust for the next split
if (_force_one_burst_per_split) // br308
{
trace0(0, ms, 110, "_force_one_burst_per_split: YES");
_lun_data(max_lb_per_split) = 1;
}
else
{
trace0(0, ms, 110, "_force_one_burst_per_split: NO");
_lun_data(max_lb_per_split) = _min(_ms_page_per_block, g_n_lb_this_xfer.u32);
}
//_profile_off(7);
return k_success;
}
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result ms_write_end_xfer() reentrant
{
//_profile_on(5);
trace0(0, ms, 10, "ms_write_end_xfer()");
//_stack_check();
// clear daken before issuing command other than wr-page-data and rd-page-data
// need to do this again here in case end burst skiped on error
_ms_register_clr_bits(ms_mode_ctl, kbm_ms_mode_ctl_daken);
if (k_success != _fmc_get_result())
return k_error;
// cds - turning off auto-xfer so that write_flush() can use
// the fmdu for the sector_copy
_mcu_register_clr_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans);
trace0(0, fmc, 0, "auto-transfer bit ==> OFF");
//_profile_on(4);
if (k_success != map_write_flush())
return g_fmc_rslt = k_error;
//_profile_off(4);
_lun_data(sensep) = &sense_none;
//_profile_off(5);
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ms_read
//
// Declaration:
// void dfa_ms_read(void);
//
// Purpose:
// Read data from the MS card.
//
// Arguments:
// None.
//
// 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 entry state of a DFA, not a FUNCTION.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_ms_read(void) reentrant
{
// profile: ~13usec
//_profile_on(6);
trace0(0, ms, 0, "dfa_ms_read()");
//_stack_check();
// _fmc_set_callback(ms_read_begin_xfer, ms_read_end_xfer, ms_read_begin_first_split, ms_read_end_split, ms_read_begin_burst, NULL, ms_read_end_burst);
_fmc_set_callback(ms_read_begin_xfer, ms_read_end_xfer, ms_read_begin_first_split, ms_read_end_split, ms_read_begin_burst, ms_rw_intra_burst, ms_read_end_burst);
//_profile_off(6);
dfa_lun_read();
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ms_write
//
// Declaration:
// void dfa_ms_write(void);
//
// Purpose:
// Write data to the MS card.
//
// Arguments:
// None.
//
// 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 entry state of a DFA, not a FUNCTION.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_ms_write(void) reentrant
{
trace0(0, ms, 10, "dfa_ms_write()");
// _fmc_set_callback(ms_write_begin_xfer, ms_write_end_xfer, ms_write_begin_first_split, ms_write_end_split, ms_write_begin_burst, NULL, ms_write_end_burst);
_fmc_set_callback(ms_write_begin_xfer, ms_write_end_xfer, ms_write_begin_first_split, ms_write_end_split, ms_write_begin_burst, ms_rw_intra_burst, ms_write_end_burst);
dfa_lun_write();
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ms_verify
//
// Declaration:
// void dfa_ms_verify(void);
//
// Purpose:
// Verify the data on the MS card.
//
// Arguments:
// None.
//
// 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 entry state of a DFA, not a FUNCTION.
// Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_ms_verify(void) reentrant
{
trace0(0, ms, 0, "dfa_ms_verify()");
//_stack_check();
// !!! callbacks not set - verify with data will CRASH!!!
_fmc_set_callback(ms_write_begin_xfer, ms_write_end_xfer, ms_write_begin_first_split, ms_write_end_split, ms_write_begin_burst, ms_rw_intra_burst, ms_write_end_burst);
dfa_lun_verify();
}
//---eof------------------------------------------------------------------------