📄 fmc.c
字号:
//------------------------------------------------------------------------------
void fmc_select_sdc() reentrant
{
#if (k_log_lun_sd < k_max_log_lun)
_mcu_begin_critical_section();
x_fmc_mode_ctl=k_fmc_mode_sdc;
TRACE1(18, fmc, 0, "select sd/mmc device. fmc_out_ctl:0x%02X fmc_mode_ctl:0x%02X", x_fmc_mode_ctl);
// throttle up the CKCON for fastest access to xdata registers
CKCON = 0x00;
_mcu_end_critical_section();
#endif
}
//+-----------------------------------------------------------------------------
// Name:
// fmc_select_nand
//
// Declaration:
// void fmc_select_nand(void);
//
// Purpose:
// Aim the fmdu at the nand controller (same as the sm controller)
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// - This is a FUNCTION, not a DFA.
// - Overrides lun_enable_mux.
// - This does NOT affect the chip select GPIO
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void fmc_select_nand() reentrant
{
#if (k_log_lun_nand < k_max_log_lun)
mcu_begin_critical_section();
x_fmc_mode_ctl= k_fmc_mode_smc;
trace1(0, nand, 0, "select nand device. fmc_mode_ctl:0x%02X", x_fmc_mode_ctl);
// slow down access to xdata registers to give hardware time to access the media
CKCON = 0x01;
media_set_active(g_ix_media_nand) ;
mcu_end_critical_section();
#endif
}
//+-----------------------------------------------------------------------------
// Name:
// fmc_abort_transfer
//
// Declaration:
// void fmc_abort_transfer(void);
//
// Purpose:
// Abort the current fmdu transfer.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
static void fmc_abort_transfer(void) reentrant;
static void fmc_abort_transfer() reentrant
{
t_udw32 remaining;
TRACE0(19, fmc, 0, "fmc_abort_transfer()");
if (!_dev_sense_vbus())
{
TRACE0(20, fmc, 0, " -- cutting power to the compact flash");
_cf_pwr_off();
//trace0(0, fmc, 0, " -- issuing device reset");
//_dev_soft_reset();
}
_mcu_begin_critical_section();
_mcu_register_clr_bits(x_fmc_ctl, (kbm_fmc_ctl_blk_xfer_en | kbm_fmc_ctl_auto_trans));
_mcu_register_wr(x_isr0, kbm_isr0_ramrd_a |kbm_isr0_ramrd_b |kbm_isr0_ramwr_a |kbm_isr0_ramwr_b);
remaining.u8.hi = _mcu_register_rd(x_fmc_cnt3);
remaining.u8.lh = _mcu_register_rd(x_fmc_cnt2);
remaining.u8.hl = _mcu_register_rd(x_fmc_cnt1);
remaining.u8.lo = _mcu_register_rd(x_fmc_cnt0);
_mscbot_set_residue(remaining.u32);
// if (g_usbrst)
// fgnd_hpbot_wait_create();
_mcu_end_critical_section();
}
//+-----------------------------------------------------------------------------
// Name:
// fmc_wait_count_down_with_timeout
//
// Declaration:
// t_result fmc_wait_count_down_with_timeout(uint16 ticks);
//
// Purpose:
// Wait for the block transfer to edecrement to zero, without yielding.
//
// Arguments:
// ticks - a uint16 representing the timeout limit
//
// Return:
// A t_result indicating:
// k_success - the ata status register logically anded with the mask equals the 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 fmc_wait_count_down_with_timeout(uint16 ticks) reentrant
{
t_sync sync;
TRACE0(21, fmc, 1, "fmc_wait_blk_count_down_with_timeout()");
thread_set_timer(ticks);
do
{
sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer);
_thread_clr_sync(sync);
if (sync & kbm_sync_usbrst)
{
TRACE0(22, fmc, 1, "fmc_wait_blk_count_down_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_abort)
{
TRACE0(23, fmc, 1, "fmc_wait_blk_count_down_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_timer)
{
TRACE0(24, fmc, 1, "fmc_wait_blk_count_down_with_timeout() - error: timeout awaiting irq");
return k_timeout;
}
//_mcu_begin_critical_section();
//TRACE4(161, fmc, 0, "fmc_cnt#: %02x%02x%02x%02x", x_fmc_cnt3, x_fmc_cnt2, x_fmc_cnt1, x_fmc_cnt0);
//_mcu_end_critical_section();
} while (_mcu_register_rd(x_fmc_cnt3) | _mcu_register_rd(x_fmc_cnt2) |
_mcu_register_rd(x_fmc_cnt1) | _mcu_register_rd(x_fmc_cnt0));
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// fmc_wait_blk_irq_with_timeout
//
// Declaration:
// t_result fmc_wait_blk_irq_with_timeout(uint16 ticks);
//
// Purpose:
// Wait for the block transfer interrupt, without yielding.
//
// Arguments:
// ticks - a uint16 representing the timeout limit
//
// Return:
// A t_result indicating:
// k_success - the ata status register logically anded with the mask equals the 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 fmc_wait_blk_irq_with_timeout(uint16 ticks) reentrant
{
t_sync sync;
TRACE0(25, fmc, 1, "fmc_wait_blk_irq_with_timeout()");
thread_set_timer(ticks);
do
{
sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer |kbm_sync_fmc_blk);
_thread_clr_sync(sync);
if (sync & kbm_sync_usbrst)
{
TRACE0(26, fmc, 1, "fmc_wait_blk_irq_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_abort)
{
TRACE0(27, fmc, 1, "fmc_wait_blk_irq_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_timer)
{
TRACE0(28, fmc, 1, "fmc_wait_blk_irq_with_timeout() - error: timeout awaiting irq");
return k_timeout;
}
#if 1
// AAA: fmc_transfer doesnt call this any more - it unrolls the function
// so i turned this optimization off to avoid breaking sd.
// added this to poll instead of taking the interrupt
if (_mcu_register_rd(x_isr0) & kbm_isr0_blk_xfer_complete)
break;
#endif
} while (!(sync & kbm_sync_fmc_blk));
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result fmc_dflt_callback() reentrant
{
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// fmc_transfer
//
// Declaration:
// t_result fmc_transfer(void);
//
// Purpose:
// Transfer data via the fmdu.
//
// Arguments:
// No parameters, but the caller must have previously called:
// _fmc_set_start_lb_8() OR _fmc_set_start_lb_32()
// AND
// _fmc_set_lb_count_8() Or _fmc_set_lb_count_32()
// AND
// _fmc_set_callback()
// AND
// _fmc_set_timeout()
// AND
// must have set both _lun_data(lun, max_lb_per_split) and _lun_data(lun, max_lb_per_burst)
//
// Return:
// A t_result indicating:
// k_success - transfer complete.
// k_usbrst - usb reset signalling was detected during the transfer.
// k_aborted - traffic occurred on the control pipe during the transfer (probably a mass storage reset).
// k_timeout - timeout limit exceeded.
//
// Notes:
// The class/subclass/protocol specifies starting logical block and the number
// of logical blocks for a read/write/verify operation. A logical block is
// analogous to a disk sector, which is 512 bytes for all of the supported flash
// cards.
//
// A "transfer" is a data move that satisfies the full amount requested via the
// protocol; e.g., read 2500 logical blocks starting from logical block 99.
// However, some drive types cannot move arbitrarily large numbers of logical blocks
// in a single command. For example, ata drives have a single byte sector count
// register and thus can only move 256 sectors (logical blocks) per command.
// Therefore, to read 300 logical blocks from an ata drive requires two read commands;
// one for 256 logical blocks, another for the remainder. Thus the transfer must
// be "split" into multiple peices, and the command issued for each split.
//
// Additionally, different drive types have differnt policies for generating
// interrupts. Some can move multiple logical blocks without generating an interrupt,
// others generate an interrupt after moving each logical block, and others after
// various numbers of logical blocks have moved. Moving some number of logical
// blocks and then getting an interrupt is called a "burst".
//
// These globals affect the operation. Don't access then directly in callbacks.
// Instead, use the _fmc_set_xxxx() and _fmc_get_xxxx() wrappers. That will
// keep the implementation opaque (knock on wood). Use _fmc_get_result to check the result.
//
// g_start_lb_this_xfer - specifies the starting logical block for the transfer
// per the protocol
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -