www.pudn.com > SMSC USB2.0.zip > sd.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.
____________________________________________________________________________
____________________________________________________________________________
sd.c - secure digital mass storage class implementation file
____________________________________________________________________________
comments tbd
____________________________________________________________________________
Revision History
Date Who Comment
________ ___ _____________________________________________________________
11/##/01 cds initial version - stubs for a few overrides.
04/28/02 tbh xdata is not initialized to zero on power up so set fmc_options to
zero at start of every transfer.
05/06/02 ds It has been noted that the power-cycling of the card is not sufficient to reset the card.
So,we roll back the change and issue the reset command along with power-cycle.
05/06/02 ds If the media is write-protected we should pass the Verify command, to ensure proper operation
in Win2k
05/09/02 ds Enabled "Emergency Exit" with setjmp when waiting for tx and rx interrupts during FS xfers
05/28/02 ds In an attempt to speed up SD, I have made the code to poll for the tx and rx bits instead of
taking an interrupt. Note that the changes are reflected in the irq_timeout fn. Also, implemented
pre-erase which speeds-up 'certain SD cards'.
06/17/02 ds The pre-erase is applicable only to SD and not MMC cards.
06/18/02 DS More error detection code added to the Read/Write parts. On a media removal made sure we are
reporting the right sense code
06/18/02 ds Added comments to explain the timeout value. Also added a margin to the timeout. This reflects
the current 1.1 xfer speed of 200 KBPS
06/19/02 ds Fixed win2k 1.1 surprise removal bug. _sd_data_loaded is reinitialized on a surprise removal
06/19/02 ds Changed the fmc_set_callback to use fmc_dflt_callback instead of NULL, BOT optimization.
06/20/02 ds Set the minimum timeout to 50 ms in g_fmc_timeout, to care of the device overhead
06/20/02 ds Since the Upper layer sets the sense code for no-media, it has been removed from SD layer.
06/25/02 ds Now that we receive a sync_abort on sd_blk_ovrrun error and crc_error, they are handled accordingly
in the SD layer.
06/25/02 ds Based on measurements set the "card programming " timeout to 1sec
06/27/02 ds USB97c210 exibited the latency issue ( a la 201). This appeared as a format issue in Mac OS 10.1.5
Thus added NOPs to bur some time after we set the bits in ep2_ctl register.
07/01/02 ds In sync with the optimization of reads and writes, the read and write dfas are now functions.
So, they shall use __thread_return_dfa a new macro which simply returns to the caller.
Also, took out the check for wr_protection on writes. This should be done in the generic lun layer.
07/11/02 ds Changed the device ID name to be consistent with recent change (by Trenton), to the drive names.
07/16/02 tbh added k_pfm_led code to de/activate led on card discovery/absence so led
operates correctly with old-n-busted OSs that don't send periodic TURs.
07/30/02 ds On a high speed read we now wait for an innak before issuing the read command. This is
to take care of slow hosts ( some wait for about 2ms after the read command to send the first IN token).
Due to lack of flow control in the SDC hardware, the sd_blk_ovrrun error occurs, forcing us to send
a read_error and fail the transfer. It has been noted that the Wincomp software does not retry a read.
This causes it to fail. This does not happen in Full speed as we take a lot of time to hand-fill the buffers.
09/11/02 ds The firing of the timer1 interrupt in the middle of 2.0 data xfer (FMDU), causes data loss and
makes it appear to the host like there is data corruption, even though the file itself is not corrupted.
So, turned off the timer for now, if we know it is an SD 2.0 read. So, the light will not blink to the desired interval on SD.
09/12/02 ds To be safe turn of timer1 even on 2.0 writes.
09/12/02 ds Manage the state of the gpio0 led, during the xfer.
09/12/02 tbh replaced strncpy() with memcpy() to save data space.
09/12/02 tbh/ds timer1 disabled during sd transfers to avoid data corruption issue. bug report #343
added comments (including this one)
09/17/02 tbh fixed improperly coded accesses to x_fmc_clk_ctl.
09/18/02 tbh bug report 343, sd data corruption. initial workaround was to
disable timer1 interrupts during sd transfers. later examination
revealed that issuing the read to the sd card *before* enabling
the block transfer is problematic due to a window of vulnerability
during which the following can occur:
if the transfer is off for too long bu the sd is reading data then
the sd card will dump its data into the bit bucket. once the
block transfer is enabled the sd card provides the desired quantity
of data, but starting from the incorrect offset. thus the data
appears corrupt. today's modification was to postpone issuing
the read command until after the block transfer is enabled.
09/19/02 tbh typo - disable was diable
10/02/02 ds Set the timeout value for data transfers to 10 seconds, following the other luns.
This value is safer than then the empirical value we had before.
10/17/02 cds updated lun_data macros to use the new vtbl and lun_data formats.
10/24/02 ds Implemented Retry of 2.0 reads, when an sd_blk_ovrrun error occurs. The new address is
computed and a multiple-block-read is issued.
============================================================================*/
#define __sd_dot_c__
#include "project.h"
#include "dev.h"
// provide vtable definition '_vtbl_cf'
code _vtbl_defn(sd);
#define sd_1point1_included
//#define Debug_On //A local directive to turn on certain debug features
//#define sd_fast_1point1
#define FS_pktsz 64
uint8 xdata _sd_card_active = k_true; //This is a flag to know if the card is not responding
uint8 xdata _sd_data_loaded = k_false; //Tells me if the buffers are already loaded
//------------------------------------------------------------------------------
// sd/mmc controller (sdc) interface registers
unsigned char volatile xdata sdc_data at_sd(F6); // rw SDC Data Register
unsigned char volatile xdata sdc_mode_ctl at_sd(F8); // rw SDC Model Control Register
unsigned char volatile xdata sdc_ctl at_sd(F9); // rw SDC Control Register
unsigned char volatile xdata sdc_cmd_rsp_buf[17] _at_ 0x3640;
//RCA bytes
uint8 xdata g_sdc_rca_h = 0x00;
uint8 xdata g_sdc_rca_l = 0x00;
uint8 xdata _sd_state = 0x00; //Tells us the current _sd_state of the card
uint8 xdata _sd_data_xfer_cmd; //Instead of passing a parameter this tells what cmd to issue
uint8 xdata _sd_write_protected = k_false; //The media could be Write Protected both in Soft and Hard way
jmp_buf xdata _sd_context; // This the context to which timeout fns will jump to on error
xdata t_udw32 xdata _sd_start_addr_this_xfer; //The device takes byte address instead of block address. This variable stores that.
//+-----------------------------------------------------------------------------
// Name:
// TBD
//
// Declaration:
// TBD
//
// Purpose:
// TBD
//
// Arguments:
// TBD
//
// Return:
// TBD
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sdc_read_rsp(uint8 length) reentrant
{
uint8 i,temp;
for(i=0;i<=length;i++)
{
temp = XBYTE[(0X3640+i)];
}
}
//+-----------------------------------------------------------------------------
// Name:
// sdc_wait_status_with_timeout
//
// Declaration:
// t_result sdc_wait_status_with_timeout(uint8 mask,uint16 ticks);
//
// Purpose:
// Poll the sdc status register to watch for specific bits being set.
//
// Arguments:
// mask - a uint8 with 1's in the bits to be compared
// ticks - a uint16 representing the timeout limit
//
// Return:
// A t_result indicating:
// k_success - the sdc status register logically anded with the mask
// k_usbreset - 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.
// Why does this not return a result? and Why does this set a global instead? This is because this fn is
// is called several levels down from the main caller, and requires a lot of code to transmit the result up
// the hierarchy. So, now we just check for the flag and return, so the highest caller may take appropriate
// action.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sdc_wait_status_with_timeout(uint8 mask, uint16 ticks) reentrant
{
uint8 status;
t_sync sync = 0;
t_sync sync1 = 0;
_stack_check();
//_stack_dump();
//TRACE2(295, sd, 1, "sdc_wait_status_with_timeout(mask:%02X ticks:%d)", mask, ticks);
// do this to get kbm_sync_abort delivered of there is traffic on the control pipe
_isr_bind_dma_owner(g_tid, kbm_sync_none);
// wait until the device is no longer busy
thread_set_timer(ticks);
_mcu_begin_critical_section();
sync = _thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer);
_mcu_end_critical_section();
status = x_sdc_stat;
//TRACE1(296, sd, 1, "The value of status %02x ",status);
while((status & mask) != mask)
{
_mcu_begin_critical_section();
sync = _thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer);
_mcu_end_critical_section();
_stack_check();
if(sync & kbm_sync_usbrst)
{
trace0(0, sd, 1, "sdc_wait_status_with_timeout() - error: kbm_sync_usbrst");
break;
}
if(sync & kbm_sync_abort)
{
trace0(0, sd, 1, "sdc_wait_status_with_timeout() - error: kbm_sync_abort");
break;
}
if(sync & kbm_sync_timer)
{
trace0(0, sd, 1, "sdc_wait_status_with_timeout() - error: hung busy");
//when a command fails init stage it could be because of a mmc card
_sd_card_active = k_false;
break;
}
status = x_sdc_stat;
// trace1(0, sd, 1, "The value of status %02x ",status);
}
if(sync) //did we get out on a failure?
{
//Reset the media here
trace0(0, sd, 1, "Resetting the SDC Block");
sdc_ctl = 0x20;
thread_set_timer(10);
while(!(sync1 & kbm_sync_timer))
{
_mcu_begin_critical_section();
sync1 = _thread_got_sync(kbm_sync_timer);
_mcu_end_critical_section();
}
_thread_clr_sync(kbm_sync_timer);
}
_thread_clr_sync(sync); //clear the synchronizers
if(sync & (kbm_sync_usbrst |kbm_sync_abort))
longjmp(_sd_context, 1); //Go to the caller dfa and return failed
//_stack_dump();
//TRACE1(301, sd, 1, "The value of status %02x ",status);
_stack_check();
//_stack_dump();
return;
}
//+-----------------------------------------------------------------------------
// Name:
// sdc_wait_irq_with_timeout
//
// Declaration:
// t_result sdc_wait_irq_with_timeout(uint16 ticks);
//
// Purpose:
// Poll for any synchronizer .
//
// Arguments:
// ticks - a uint16 representing the timeout limit
//
// Return:
// A t_result indicating:
// k_success - the sync was spotted.
// k_usbreset - 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
//------------------------------------------------------------------------------
#ifndef sd_fast_1point1
t_result sdc_wait_irq_with_timeout(uint8 irq_name, uint16 ticks) reentrant
{
t_sync sync;
//TRACE2(302, sd, 1, "sd_wait_irq_with_timeout(ticks:%d) for %02x", ticks, irq_name);
// do this to get kbm_sync_abort delivered of there is traffic on the control pipe
_isr_bind_dma_owner(g_tid, kbm_sync_none);
thread_set_timer(ticks);
sync = kbm_sync_none;
//while(!(sync & irq_name))
while(!(_mcu_register_rd(x_isr0) & irq_name))
{
sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer);
_thread_clr_sync(sync);
if(sync & kbm_sync_usbrst)
{
trace0(0, sd, 1, "sd_wait_irq_with_timeout() - error: kbm_sync_usbrst");
}
if(sync & kbm_sync_abort)
{
trace0(0, sd, 1, "sd_wait_irq_with_timeout() - error: kbm_sync_abort");
}
if(sync & kbm_sync_timer)
{
trace0(0, sd, 1, "sd_wait_irq_with_timeout() - error: timeout awaiting irq");
return k_timeout;
}
if(sync & (kbm_sync_usbrst |kbm_sync_abort))
longjmp(_sd_context, 1); //Go to the caller dfa and return failed
}
trace0(0, sd, 1, "sd_wait_irq_with_timeout() - got the irq");
return k_success;
}
#endif
//+-----------------------------------------------------------------------------
// Name:
// sd_pre_cmd
//
// Declaration:
// void sd_pre_cmd() reentrant
//
// Purpose:
// Prepare the device before issuing a command
//
// Arguments:
// None
//
// Return:
// None
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_pre_cmd() reentrant
{
trace0(0, sd, 1, "+sd_pre_cmd");
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_crc_err);
sdc_ctl &= ~kbm_sdc_id_data;
sdc_wait_status_with_timeout(kbm_sdc_stat_crd_rdy,300);
sdc_wait_status_with_timeout(kbm_sdc_stat_cmd_rdy,300);
trace0(0, sd, 1, "-sd_pre_cmd");
}
//+-----------------------------------------------------------------------------
// Name:
// sd_display_rsp_buf
//
// Declaration:
// void sd_display_rsp_buf() reentrant
//
// Purpose:
// Dumps out the contents of the cmd_rsp buffer
//
// Arguments:
// None
//
// Return:
// None
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_display_rsp_buf() reentrant
{
trace1(0, sd, 2, "Response Buffer[0] = %02x",sdc_cmd_rsp_buf[0]);
trace1(0, sd, 2, "Response Buffer[1] = %02x",sdc_cmd_rsp_buf[1]);
trace1(0, sd, 2, "Response Buffer[2] = %02x",sdc_cmd_rsp_buf[2]);
trace1(0, sd, 2, "Response Buffer[3] = %02x",sdc_cmd_rsp_buf[3]);
trace1(0, sd, 2, "Response Buffer[4] = %02x",sdc_cmd_rsp_buf[4]);
trace1(0, sd, 2, "Response Buffer[5] = %02x",sdc_cmd_rsp_buf[5]);
trace1(0, sd, 2, "Response Buffer[6] = %02x",sdc_cmd_rsp_buf[6]);
trace1(0, sd, 2, "Response Buffer[7] = %02x",sdc_cmd_rsp_buf[7]);
trace1(0, sd, 2, "Response Buffer[8] = %02x",sdc_cmd_rsp_buf[8]);
trace1(0, sd, 2, "Response Buffer[9] = %02x",sdc_cmd_rsp_buf[9]);
trace1(0, sd, 2, "Response Buffer[10] = %02x",sdc_cmd_rsp_buf[10]);
trace1(0, sd, 2, "Response Buffer[11] = %02x",sdc_cmd_rsp_buf[11]);
trace1(0, sd, 2, "Response Buffer[12] = %02x",sdc_cmd_rsp_buf[12]);
trace1(0, sd, 2, "Response Buffer[13] = %02x",sdc_cmd_rsp_buf[13]);
trace1(0, sd, 2, "Response Buffer[14] = %02x",sdc_cmd_rsp_buf[14]);
trace1(0, sd, 2, "Response Buffer[15] = %02x",sdc_cmd_rsp_buf[15]);
trace1(0, sd, 2, "Response Buffer[16] = %02x",sdc_cmd_rsp_buf[16]);
}
//+-----------------------------------------------------------------------------
// Name:
// sd_app_cmd
//
// Declaration:
// void sd_app_cmd() reentrant
//
// Purpose:
// Prepare the device before issuing an app specific command
//
// Arguments:
// None
//
// Return:
// None
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_app_cmd() reentrant
{
trace0(0, sd, 1, "+sd_app_cmd");
sd_pre_cmd();
//fill the command buffer
sdc_cmd_rsp_buf[0] = 0x77;
sdc_cmd_rsp_buf[1] = g_sdc_rca_h;
sdc_cmd_rsp_buf[2] = g_sdc_rca_l;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
_sd_wait_48b_resp();
sd_display_rsp_buf();
sdc_read_rsp(5);
trace0(0, sd, 1, "-sd_app_cmd");
}
//+-----------------------------------------------------------------------------
// Name:
// sd_get_status
//
// Declaration:
// void sd_get_status() reentrant
//
// Purpose:
// Get the current State of the SD Device
//
// Arguments:
// None
//
// Return:
//
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_get_status() reentrant
{
trace0(0, sd, 1, "+ sd_get_status()");
_stack_check();
sd_pre_cmd();
_stack_check();
//fill the command buffer
sdc_cmd_rsp_buf[0] = 0x4d;
sdc_cmd_rsp_buf[1] = g_sdc_rca_h;
sdc_cmd_rsp_buf[2] = g_sdc_rca_l;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
_sd_wait_48b_resp();
//sd_display_rsp_buf();
_sd_state = sdc_cmd_rsp_buf[3] & 0x1e;
_sd_state = _sd_state >> 1;
#ifdef Debug_On
switch(_sd_state)
{
case k_sdc_state_stby:
trace0(0, sd, 1, "Standby state");
break;
case k_sdc_state_tran:
trace0(0, sd, 1, "Transfer state");
break;
case k_sdc_state_data:
trace0(0, sd, 1, "Data state");
break;
case k_sdc_state_rcv:
trace0(0, sd, 1, "Receive state");
break;
case k_sdc_state_prg:
trace0(0, sd, 1, "Program state");
break;
case k_sdc_state_dis:
trace0(0, sd, 1, "Disable state");
break;
default:
trace1(0, sd, 1, "Unknown state %d",_sd_state);
break;
}
if(sdc_cmd_rsp_buf[3] & 0x01)
{
trace0(0, sd, 0, "Ready for data!!");
} else
{
trace0(0, sd, 0, "Not Ready for data!!");
}
#endif
sdc_read_rsp(5);
trace0(0, sd, 1, "- sd_get_status()");
return;
}
//+-----------------------------------------------------------------------------
// Name:
// sd_set_bus_width
//
// Declaration:
// void sd_set_bus_width(uint8 BusWidth) reentrant
//
// Purpose:
// Set the data bus width to either single line or four data lines.
//
// Arguments:
// None
//
// Return:
//
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_set_bus_width(uint8 BusWidth) reentrant
{
trace1(0, sd, 1, "Set Bus width to %d ", BusWidth);
sd_app_cmd();
sd_pre_cmd();
sdc_cmd_rsp_buf[0] = 0x46;
sdc_cmd_rsp_buf[1] = 0x00;
sdc_cmd_rsp_buf[2] = 0x00;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = BusWidth;
_sd_wait_48b_resp();
sd_display_rsp_buf();
sdc_read_rsp(5);
}
//+-----------------------------------------------------------------------------
// Name:
// sd_stop_transfer
//
// Declaration:
// void sd_stop_transfer() reentrant
//
// Purpose:
// Stop the data xfer
//
// Arguments:
// None
//
// Return:
//
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_stop_transfer() reentrant
{
trace0(0, sd, 1, "Stop the transfer");
sd_pre_cmd();
sdc_cmd_rsp_buf[0] = 0x4c;
sdc_cmd_rsp_buf[1] = 0x00;
sdc_cmd_rsp_buf[2] = 0x00;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
_sd_wait_48b_resp();
sd_display_rsp_buf();
sd_get_status();
sdc_read_rsp(5);
}
//+-----------------------------------------------------------------------------
// Name:
// sd_init_controller
//
// Declaration:
// void sd_init_controller(void) reentrant
//
// Purpose:
// tbd
//
// Arguments:
// None
//
// Return:
//
//
// Notes:
// tbd
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sd_init_controller(void) reentrant
{
trace0(0, cf, 0, "cf_init_controller()");
// copy string name into the controller device ID
memcpy(_lun_data_rd(k_lun_sd, device_id), "SD/MMC", k_lun_max_devid_sz);
memcpy(_lun_data_rd(k_lun_mmc, device_id), "SD/MMC", k_lun_max_devid_sz);
_lun_data_wr(k_lun_sd, device_type, k_device_type_sd);
_lun_data_wr(k_lun_mmc, device_type, k_device_type_mmc);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#include "dev.h"
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// should be in sd.h with all other sd register bit definitions
#define kbm_sdc_ctl_sdc_rst 0x20
t_result tbh_wait_status_with_timeout(uint8 mask, uint16 ticks) reentrant;
t_result tbh_wait_status_with_timeout(uint8 mask, uint16 ticks) reentrant
{
uint8 status;
t_sync sync;
trace0(0, sd, 10, "tbh_wait_status_with_timeout()");
// do this to get kbm_sync_abort delivered of there is traffic on the control pipe
_isr_bind_dma_owner(g_tid, kbm_sync_none);
thread_set_timer(ticks+1);
do
{
_mcu_begin_critical_section();
sync = _thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer);
_mcu_end_critical_section();
thread_clr_sync(sync);
status = _sd_register_rd(x_sdc_stat);
if(sync & kbm_sync_abort)
{
trace0(0, sd, 10, "tbh_wait_status_with_timeout() - error: kbm_sync_abort");
// must delay some after this, but unknown how long, assume a few instruction cycles...
_sd_register_wr(sdc_ctl, kbm_sdc_ctl_sdc_rst);
return k_aborted;
}
if(sync & kbm_sync_usbrst)
{
trace0(0, sd, 10, "tbh_wait_status_with_timeout() - error: kbm_sync_usbrst");
// must delay some after this, but unknown how long, assume a few instruction cycles...
_sd_register_wr(sdc_ctl, kbm_sdc_ctl_sdc_rst);
return k_usbreset;
}
if(sync & kbm_sync_timer)
{
trace0(0, sd, 10, "tbh_wait_status_with_timeout() - error: kbm_sync_timer");
// must delay some after this, but unknown how long, assume a few instruction cycles...
_sd_register_wr(sdc_ctl, kbm_sdc_ctl_sdc_rst);
return k_timeout;
}
} while((status & mask) != mask);
return k_success;
}
//------------------------------------------------------------------------------
// issuing CMD0 - go idle - is the same as power on reset
// power cycling the card is easier and faster
//------------------------------------------------------------------------------
void dfa_sd_reset() reentrant
{
trace0(0, sd, 99, "sd_reset()");
//Jump to this location on an "Emergency Exit" due to sync_abort or sync_usbreset
if(setjmp(_sd_context))
{
trace0(0, sd, 99, "EMERGENCY EXIT!!");
thread_return_dfa(k_error);
}
_mcu_register_clr_bits(x_fmc_clk_ctl, k_fmc_clk_ctl_sd_disable);
_mcu_register_set_bits(x_fmc_clk_ctl, k_fmc_clk_ctl_sd_200khz);
_sd_register_set_bits(sdc_ctl, kbm_sdc_bus_type);
g_sdc_rca_h = 0x00;
g_sdc_rca_l = 0x00;
_sd_write_protected = k_false;
_sd_card_active = k_true;
_sd_data_loaded = k_false;
_sd_state = 0x00;
_sd_pwr_on();
// can afford a 2msec blocking loop here, hopefully
thread_set_timer(2);
while(!thread_got_sync(kbm_sync_timer));
//Now issue the reset command as well
trace1(0, sd, 1, "The sdc_ctl register %02x",sdc_ctl);
trace1(0, sd, 1, "The crd_ps register %02x",_mcu_register_rd(x_crd_ps));
sd_pre_cmd();
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
//fill the command buffer
sdc_cmd_rsp_buf[0] = 0x40;
sdc_cmd_rsp_buf[1] = 0x00;
sdc_cmd_rsp_buf[2] = 0x00;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
sd_display_rsp_buf();
//reset mode control register
sdc_mode_ctl = 0;
sdc_mode_ctl |= (kbm_sdc_cmd_no_rsp | kbm_sdc_rsp_crc_ds); // Disable Crc 7
thread_set_timer(1);
while(!(thread_got_sync(kbm_sync_timer)));
thread_clr_sync(kbm_sync_timer);
thread_return_dfa(k_success);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void dfa_sd_initialize() reentrant
{
t_result rslt;
//Jump to this location on an "Emergency Exit" due to sync_abort or sync_usbreset
trace0(0, sd, 99, "dfa_sd_initialize()");
// assmume no media
_lun_data_wr(k_lun_sd, media, (_lun_data_rd(k_lun_sd, media)&~(kbm_lun_media_present |kbm_lun_media_unknown |kbm_lun_media_changed)));
_lun_data_wr(k_lun_mmc, media, (_lun_data_rd(k_lun_mmc, media)&~(kbm_lun_media_present |kbm_lun_media_unknown |kbm_lun_media_changed)));
// clear the rsp buf byte 1 so we don't see remnant of previous operation
sdc_cmd_rsp_buf[1] = 0;
// monitor the card's busy bit - $$$need a symbol instead of a hex constant...
while(!(sdc_cmd_rsp_buf[1] & 0x80))
{
trace1(0, sd, 0, "top of while loop, _sd_card_active:%d", _sd_card_active);
// probe for SD card. if not found probe for MMC card.
if(k_lun_sd == g_active_lun)
{
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_crc_err);
_sd_register_clr_bits(sdc_ctl, kbm_sdc_id_data);
if(k_success != tbh_wait_status_with_timeout(kbm_sdc_stat_crd_rdy, 5))
goto SWITCH_TO_MMC;
if(k_success != tbh_wait_status_with_timeout(kbm_sdc_stat_cmd_rdy, 5))
goto SWITCH_TO_MMC;
sdc_cmd_rsp_buf[0] = 0x77;
sdc_cmd_rsp_buf[1] = g_sdc_rca_h;
sdc_cmd_rsp_buf[2] = g_sdc_rca_l;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
sdc_mode_ctl = 0;
sdc_mode_ctl |= kbm_sdc_cmd_48b_rsp;
rslt = tbh_wait_status_with_timeout(kbm_sdc_stat_rsp_rdy, 5);
sdc_read_rsp(5);
if(k_timeout == rslt)
{
SWITCH_TO_MMC:
trace0(0, sd, 0, "try mmc...");
_lun_map_log2phy(k_log_lun_sd, k_lun_mmc);
//g_active_lun = k_lun_mmc;
lun_set_active(k_lun_mmc);
_sd_card_active = k_true;
} else
if(k_success != rslt)
goto EXIT_NO_MEDIA;
}
// issue ACMD41
trace0(0, sd, 1, "Issuing ACMD41");
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_crc_err);
_sd_register_clr_bits(sdc_ctl, kbm_sdc_id_data);
if(k_success != tbh_wait_status_with_timeout(kbm_sdc_stat_crd_rdy, 5))
goto EXIT_NO_MEDIA;
if(k_success != tbh_wait_status_with_timeout(kbm_sdc_stat_cmd_rdy, 5))
goto EXIT_NO_MEDIA;
if(k_lun_mmc == g_active_lun)
sdc_cmd_rsp_buf[0] = 0x41;
else
sdc_cmd_rsp_buf[0] = 0x69;
sdc_cmd_rsp_buf[1] = 0x80; // Voltage range 2.0 - 2.1
sdc_cmd_rsp_buf[2] = 0xFF;
sdc_cmd_rsp_buf[3] = 0x80;
sdc_cmd_rsp_buf[4] = 0x00;
sd_display_rsp_buf();
sdc_mode_ctl = 0;
sdc_mode_ctl |= (kbm_sdc_cmd_48b_rsp | kbm_sdc_rsp_crc_ds);
if(k_success != tbh_wait_status_with_timeout(kbm_sdc_stat_rsp_rdy, 5))
goto EXIT_NO_MEDIA;
sdc_read_rsp(5);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
}
// was there a card in the slot? if so g_active_lun is set to the correct phy lun index.
if(_sd_card_active)
{
// found a card
// clear the media changed flag so the framework will move on and establish the geometry
_lun_data(media) |= (kbm_lun_media_present |kbm_lun_media_unknown);
// need to set sense code here to get it reported (different from other luns)
_lun_data(sensep) = &sense_media_change;
switch(g_active_lun)
{
case k_lun_sd:
trace0(0, sd, 99, "media is SD");
_mcu_register_set_bits(x_crd_ps, kbm_crd_ps_sd);
break;
case k_lun_mmc:
trace0(0, sd, 99, "media is MMC");
_mcu_register_set_bits(x_crd_ps, kbm_crd_ps_mmc);
break;
}
}
irq_control(k_irq_sd_insert_eject, kbm_irqctl_clear |kbm_irqctl_unmask);
trace0(0, sd, 99, "media");
#ifdef k_pfm_led
_mcu_register_set_bits(x_gpiob_out, kbm_gpio15); //on
#endif
thread_return_dfa(k_success);
EXIT_NO_MEDIA:
trace0(0, sd, 99, "no media");
_sd_pwr_off();
_lun_map_log2phy(k_log_lun_sd, k_lun_sd);
irq_control(k_irq_sd_insert_eject, kbm_irqctl_clear |kbm_irqctl_unmask);
#ifdef k_pfm_led
_mcu_register_clr_bits(x_gpiob_out, kbm_gpio15); //off
#endif
thread_return_dfa(k_success);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void dfa_sd_identify_device() reentrant
{
uint8 i =0;
//local variables for calculating the size
uint8 read_bl_len, c_size_mult;
uint16 c_size, block_len, mult;
uint32 blocknr;
uint8 Result = 0;
//Jump to this location on an "Emergency Exit" due to sync_abort or sync_usbreset
if(setjmp(_sd_context))
{
trace0(0, sd, 0, "EMERGENCY EXIT!!");
thread_return_dfa(k_error);
}
trace0(0, sd, 1, "+sd_identify_device()");
//This will det the identification data from the sd device
trace1(0, sd, 1, "The sdc_ctl register %02x",sdc_ctl);
sd_pre_cmd();
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sdc_cmd_rsp_buf[0] = 0x42;
sdc_cmd_rsp_buf[1] = 0x00;
sdc_cmd_rsp_buf[2] = 0x00;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
sdc_cmd_rsp_buf[5] = 0x00;
//sd_display_rsp_buf();
//reset mode control register
sdc_mode_ctl = 0;
//ready to receive the response
sdc_mode_ctl |= (kbm_sdc_cmd_136b_rsp );
trace1(0, sd, 1, "The sdc_mode_ctl register %02x",sdc_mode_ctl);
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sdc_wait_status_with_timeout(kbm_sdc_stat_rsp_rdy,300);
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sdc_read_rsp(17);
//sd_display_rsp_buf();
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
//Issue CMD3 Or GetRCA
trace1(0, sd, 1, "The sdc_ctl register %02x",sdc_ctl);
sd_pre_cmd();
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
//If the device is mmc then we need to preset the rca
if(g_active_lun == k_lun_mmc)
{
g_sdc_rca_h = 0x01;
g_sdc_rca_l = 0x02;
}
sdc_cmd_rsp_buf[0] = 0x43;
sdc_cmd_rsp_buf[1] = g_sdc_rca_h;
sdc_cmd_rsp_buf[2] = g_sdc_rca_l;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
sdc_cmd_rsp_buf[5] = 0x00;
//sd_display_rsp_buf();
_sd_wait_48b_resp();
if(g_active_lun == k_lun_sd)
{
g_sdc_rca_h = sdc_cmd_rsp_buf[1];
g_sdc_rca_l = sdc_cmd_rsp_buf[2];
}
//sd_display_rsp_buf();
sdc_read_rsp(5);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
//sd_get_status();
//sdc_read_rsp(17);
//SEND_CSD or CMD9
trace0(0, sd, 1, "Issue SEND_CSD");
sd_pre_cmd();
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sdc_cmd_rsp_buf[0] = 0x49;
sdc_cmd_rsp_buf[1] = g_sdc_rca_h;
sdc_cmd_rsp_buf[2] = g_sdc_rca_l;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
sdc_cmd_rsp_buf[5] = 0x00;
//reset mode control register
sdc_mode_ctl = 0;
//ready to receive the response
sdc_mode_ctl |= (kbm_sdc_cmd_136b_rsp);
trace1(0, sd, 1, "The sdc_mode_ctl register %02x",sdc_mode_ctl);
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sdc_wait_status_with_timeout(kbm_sdc_stat_rsp_rdy,300);
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sd_display_rsp_buf();
//Calculate LBA max
read_bl_len = (sdc_cmd_rsp_buf[6] & 0x0f);
c_size = (sdc_cmd_rsp_buf[7] & 0x03);
c_size = (c_size << 10);
c_size += ((uint16)sdc_cmd_rsp_buf[8] << 2);
c_size += ((sdc_cmd_rsp_buf[9] & 0xc0) >> 6);
c_size &= 0x0fff;
c_size_mult = (sdc_cmd_rsp_buf[10] & 0x03);
c_size_mult = (c_size_mult << 1);
c_size_mult += ((sdc_cmd_rsp_buf[11] & 0x80) >> 7);
trace3(0, sd, 1, " The read_bl_len is %d , c_size is %04x, c_size_mult : %d ", read_bl_len,c_size,c_size_mult);
block_len = (1 << read_bl_len);
mult = (1 << (c_size_mult + 2));
trace2(0, sd, 1, " Block_len is %d, mult = %d",block_len, mult);
blocknr = (((uint32)c_size + (uint32)1) * (uint32)mult);
trace2(0, sd, 1, "the blocknr is %04x%04x", _hw(blocknr),_lw(blocknr));
blocknr = blocknr - (uint32) 1;
trace2(0, sd, 1, "the blocknr is %04x%04x", _hw(blocknr),_lw(blocknr));
_lun_data(capacity).lba_max.u32 = blocknr;
_lun_data(capacity).lba_sz.u32 = block_len;
trace2(0, sd, 1, "Total User-addressable Sectors: %04X%04X", _hw(_lun_data(capacity).lba_max.u32), _lw(_lun_data(capacity).lba_max.u32));
//Is the media write protected?
//Check for hardware write protection...
if(_mcu_register_rd(x_media_sts) & 0x01)
_sd_write_protected = k_true;
//Check for software write protection
if((sdc_cmd_rsp_buf[15] & 0x04) || (sdc_cmd_rsp_buf[15] & 0x08))
_sd_write_protected = k_true;
if(_sd_write_protected == k_true)
{
_lun_data(media) |= kbm_lun_media_wrprot;
} else
{
_lun_data(media) &= ~kbm_lun_media_wrprot;
}
sdc_read_rsp(17);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
//Put the device into transfer mode and get ready to roll
sd_get_status();
//select the crd
sd_pre_cmd();
sdc_cmd_rsp_buf[0] = 0x47;
sdc_cmd_rsp_buf[1] = g_sdc_rca_h;
sdc_cmd_rsp_buf[2] = g_sdc_rca_l;
sdc_cmd_rsp_buf[3] = 0x00;
sdc_cmd_rsp_buf[4] = 0x00;
sd_display_rsp_buf();
trace1(0, sd, 1, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
_sd_wait_48b_resp();
sd_display_rsp_buf();
sd_get_status();
sdc_read_rsp(5);
//**********************************
//Set the block length
trace0(0, sd, 1, "Set the block length to 512")
sd_pre_cmd();
sdc_cmd_rsp_buf[0] = 0x50;
sdc_cmd_rsp_buf[1] = 0x00;
sdc_cmd_rsp_buf[2] = 0x00;
sdc_cmd_rsp_buf[3] = 0x02;
sdc_cmd_rsp_buf[4] = 0x00;
//sd_display_rsp_buf();
trace1(0, sd, 0, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
_sd_wait_48b_resp();
sd_display_rsp_buf();
sd_get_status();
sdc_read_rsp(5);
//********************************************
//set the data bus to 4 bit wide
if(g_active_lun == k_lun_sd)
{
sd_set_bus_width(k_four_data_lines);
}
sd_get_status();
_lun_data(media) &= ~kbm_lun_media_unknown;
_mcu_register_clr_bits(x_fmc_clk_ctl, k_fmc_clk_ctl_sd_disable);
_mcu_register_set_bits(x_fmc_clk_ctl, k_fmc_clk_ctl_sd_20mhz);
//Enough time to let the clk freq change... should be changed to more accurate time.
thread_set_timer(1);
while(!(thread_got_sync(kbm_sync_timer)));
thread_clr_sync(kbm_sync_timer);
thread_return_dfa(k_success);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void sd_pre_erase() reentrant
{
trace0(0, sd, 0, "+sd_pre_erase();");
sd_app_cmd();
sd_pre_cmd();
sdc_cmd_rsp_buf[0] = 0x57; //pre_ERASE
sdc_cmd_rsp_buf[1] = 0X00;
sdc_cmd_rsp_buf[2] = 0X00;
sdc_cmd_rsp_buf[3] = g_n_lb_this_split.u8.hl;
sdc_cmd_rsp_buf[4] = g_n_lb_this_split.u8.lo;
_sd_wait_48b_resp();
sd_display_rsp_buf();
sdc_read_rsp(5);
return;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result sd_read_write_begin_xfer() reentrant
{
uint32 n_bytes_this_xfer = 0;
//The max lbs we can transfer is however much the host asks for
if(sie_is_high_speed())
{
// timer1 disabled during sd transfers to avoid data corruption issue. bug report #343
#if 0
//Turn off the timer interrupt for 2.0 reads
irq_control(k_irq_cpu_t1, kbm_irqctl_mask);
//Put the led in the opposite state of idle
if (g_led_stays_on) //opposite of idle state
gpio_clrbit(0);
else
gpio_setbit(0);
#endif
_lun_data(max_lb_per_split) =_fmc_get_lb_count_32();
_lun_data(max_lb_per_burst) = _fmc_get_lb_count_32();
} else
{
if(_sd_data_xfer_cmd == k_sdc_cmd_write_mult_blocks) // we can issue mult write cmd
{
_lun_data(max_lb_per_split) = _fmc_get_lb_count_32();
_lun_data(max_lb_per_burst) = 1;
//Turn off Auto xfer and exit on count zero
_fmc_set_options(kbm_fmc_disable_auto_xfer |kbm_fmc_end_burst_on_count_down |kbm_fmc_xfer_512_byte_pkt);
} else
{ //1.1 reads
_lun_data(max_lb_per_split) = 1;
_lun_data(max_lb_per_burst) = 1;
//Turn off Auto xfer
_fmc_set_options(kbm_fmc_disable_auto_xfer |kbm_fmc_xfer_512_byte_pkt);
trace1(0, sd, 3, "Setting the 512 byte pkt bit.. %02x", g_fmc_options);
}
}
//Even though the timeout should be calculated based on the CSD register, we shall calculate based on 1.1
//transfer speed. Currently we are at 200kBPS and this is the slowest part of the equation.
//On future releases, when we have overcome the hardware limitations, we shall calculate the timeout using
//the media-dependant values from the CSD register.
//Since any 16 or 32 bit computation slows down the reads/writes.. this value is computed offline
//It takes 2.5 ms to xfer a block of data at 200 KBPS. Let us round it to 3 ms. The multiply by 2 to add a margin.
//g_fmc_timeout = ( 6 * _fmc_get_lb_count_32());
// if(g_fmc_timeout < 250)
// g_fmc_timeout = 250; // Set the minimum timeout to 50 ms, to care of the device overhead
//The speeds of cards vary. So the timeout value is being set to a big number 10 sec, following the
//other luns
_fmc_set_timeout(10000);
trace1(0, sd, 0, "Setting the timeout value to.. %04x", g_fmc_timeout);
//Clear and unmask the CRC error interrupt
irq_control(k_irq_fmc_sdc_crc_err, kbm_irqctl_clear |kbm_irqctl_unmask);
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result sd_read_write_end_xfer() reentrant
{
t_result Result = 0;
trace0(0, sd, 3, "sd_read_write_end_xfer");
//Did we get here on a failure?
if(k_success !=_fmc_get_result())
{
//did the media get removed
if(!(_mcu_register_rd(x_crd_ps) & (kbm_crd_ps_sd |kbm_crd_ps_mmc)))
return _fmc_get_result();
//Issue a get status to see if the device is alive and kicking ?
sd_get_status();
//Did a CRC Error occur? or Did we exit on a sd_blk_ovrrun error Or the card is dead?
if((_mcu_register_rd(x_sdc_stat) & kbm_sdc_stat_crc_err) || (_mcu_register_rd(x_fmc_err) & kbm_fmc_err_sd_blk_ovrun)
|| (_sd_card_active == k_false))
{
if(_sd_data_xfer_cmd == k_sdc_cmd_write_mult_blocks)
{
_lun_data(sensep) = &sense_write_error;
} else
{
//if the sd_blk_ovrrun error occurred there are atleast 2 blocks that were not received by the host
//This has not been observed in 1.1 speeds as we hand fill the buffers
if((_mcu_register_rd(x_fmc_err) & kbm_fmc_err_sd_blk_ovrun) && sie_is_high_speed())
{
_mscbot_incr_residue(0x400);
}
_lun_data(sensep) = &sense_read_error;
}
}
}
//We are done with the data transfer... so issue the stop command
//NB:- The SD spec says in section 4.3.3 'Some cards may require long an unpredictable times to write a block of data"
// So, how long should we wait? On trial and error basis I have set the timeout to 1 sec. We have good
// reasons now why lesser values will not work.
sdc_wait_status_with_timeout(kbm_sdc_stat_crd_rdy,1000);
//Only on 2.0 speeds and in writes
if(sie_is_high_speed() || ( _sd_data_xfer_cmd == k_sdc_cmd_write_mult_blocks))
sd_stop_transfer();
// timer1 disabled during sd transfers to avoid data corruption issue. bug report #343
#if 0
if(sie_is_high_speed())
{
//Turn on the timer interrupt
irq_control(k_irq_cpu_t1, kbm_irqctl_unmask);
if (g_led_stays_on) //restore to idle state
gpio_setbit(0);
else
gpio_clrbit(0);
}
#endif
return _fmc_get_result();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result sd_read_write_begin_split() reentrant
{
trace0(0, sd, 3, "sd_read_write_begin_split");
#ifdef Debug_On
gpio_bit_is_output(5);
gpio_setbit(5);
#endif
//did the media get removed
if((_sd_card_active == k_false)||(!(_mcu_register_rd(x_crd_ps) & (kbm_crd_ps_sd |kbm_crd_ps_mmc))))
return k_error;
//issue the cmd
//check to see if the device is done with previous transfer
if(!(x_sdc_stat & kbm_sdc_stat_crd_rdy))
sdc_wait_status_with_timeout(kbm_sdc_stat_crd_rdy,1000);
//we have some data to start with ... so do the prep
trace1(0, tm, 0, "@%d Start wait state tran", g_cdm0);
sd_get_status();
while((_sd_state != k_sdc_state_tran) && (_sd_card_active == k_true))
{
sd_get_status();
}
trace1(0, tm, 3, "@%d End wait state tran", g_cdm0);
//did the media get removed
if(_sd_card_active == k_false)
return k_error;
//Issue the Read/write command CMD18
trace1(0, sd, 3, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
//if it is a write issue pre erase
if((_sd_data_xfer_cmd == k_sdc_cmd_write_mult_blocks) && (g_active_lun == k_lun_sd))
sd_pre_erase();
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
if(g_active_lun == k_lun_sd)
sdc_ctl |= (kbm_sdc_id_data | kbm_sdc_bus_type);
else
sdc_ctl |= (kbm_sdc_id_data);
trace1(0, sd, 3, "The fmc_clk_ctl register %02x",x_fmc_clk_ctl);
trace1(0, sd, 3, "The sdc_ctl register %02x",sdc_ctl);
//sdc_wait_status_with_timeout(kbm_sdc_stat_crd_rdy,1000);
if(!(x_sdc_stat & kbm_sdc_stat_cmd_rdy))
sdc_wait_status_with_timeout(kbm_sdc_stat_cmd_rdy,1000);
_sd_start_addr_this_xfer.u32 = _fmc_get_start_lb_32();
trace2(0, sd, 3, "read/write addr:%04X%04X ", _hw(_sd_start_addr_this_xfer.u32), _lw(_sd_start_addr_this_xfer.u32));
_sd_start_addr_this_xfer.u32 = _sd_start_addr_this_xfer.u32 * (uint32) 512;
trace2(0, sd, 3, "read/write addr:%04X%04X ", _hw(_sd_start_addr_this_xfer.u32), _lw(_sd_start_addr_this_xfer.u32));
sdc_cmd_rsp_buf[0] = _sd_data_xfer_cmd;
sdc_cmd_rsp_buf[1] = _sd_start_addr_this_xfer.u8.hi;
sdc_cmd_rsp_buf[2] = _sd_start_addr_this_xfer.u8.lh;
sdc_cmd_rsp_buf[3] = _sd_start_addr_this_xfer.u8.hl;
sdc_cmd_rsp_buf[4] = _sd_start_addr_this_xfer.u8.lo;
sd_display_rsp_buf();
trace1(0, sd, 3, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
trace0(0, sd, 0, "I am HERE!!!");
//Not calling the macro coz we have to wait a little longer for the response
// _sd_wait_48b_resp();
sdc_mode_ctl = 0;
trace1(0, sd, 0, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
sdc_mode_ctl |= kbm_sdc_cmd_48b_rsp;
trace1(0, sd, 0, "The sdc_mode_ctl register %02x",sdc_mode_ctl);
sdc_wait_status_with_timeout(kbm_sdc_stat_rsp_rdy,2000);
trace1(0, sd, 0, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
//did the media get removed
if(_sd_card_active == k_false)
return k_error;
trace1(0, sd, 3, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_rsp_rdy);
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_crc_err);
_mcu_register_clr_bits(x_sdc_stat_msk,kbm_sdc_stat_crc_err);
trace1(0, sd, 3, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
trace1(0, sd, 3, "The stat msk register %02x",x_sdc_stat_msk);
#ifdef Debug_On
gpio_clrbit(5);
#endif
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
xdata t_udw32 _current_byte_count;
t_result sd_read_intra_burst() reentrant
{
//get the buffer ready to receive data
trace0(0, sd, 3, "sd_read_intra_burst");
if (!sie_is_high_speed())
{
#ifdef k_dbg_on
dbg_bufferstat();
#endif
_mcu_register_clr_bits(x_ep2_ctl, kbm_ep2_ctl_ramwr_tog | kbm_ep2_ctl_rdtog_valid);
_mcu_register_set_bits(x_ep2_ctl, kbm_ep2_ctl_wrtog_valid);
_mcu_register_wr(x_isr0, kbm_isr0_ramwr_a);
#ifdef k_dbg_on
dbg_bufferstat();
#endif
}
else
{
//make a copy of this register for read retries
_current_byte_count.u8.hi = _mcu_register_rd(x_fmc_cnt3);
_current_byte_count.u8.lh = _mcu_register_rd(x_fmc_cnt2);
_current_byte_count.u8.hl = _mcu_register_rd(x_fmc_cnt1);
_current_byte_count.u8.lo = _mcu_register_rd(x_fmc_cnt0);
}
return sd_read_write_begin_split();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint8 k;
uint8 xdata * data data_ptr;
uint8 xdata temp_buf[64];
t_result sd_read_end_burst() reentrant
{
//allocate 64 bytes of xdata space for the temporary holder
uint8 n, Result = 0;
uint16 offset = 0;
t_udw32 n_bytes;
trace0(0, sd, 3, "sd_read_end_burst");
g_cdm0 = 0;
//Did a CRC Error occur?
if (_mcu_register_rd(x_sdc_stat) & kbm_sdc_stat_crc_err)
{
trace0(0, sd, 0, "A CRC Error occurred");
return k_error;
}
//Just for High speed
if (sie_is_high_speed())
{
if (_mcu_register_rd(x_fmc_err) & kbm_fmc_err_sd_blk_ovrun)
{
//stop the current transfer
sd_stop_transfer();
n_bytes.u8.hi = _mcu_register_rd(x_fmc_cnt3);
n_bytes.u8.lh = _mcu_register_rd(x_fmc_cnt2);
n_bytes.u8.hl = _mcu_register_rd(x_fmc_cnt1);
n_bytes.u8.lo = _mcu_register_rd(x_fmc_cnt0);
trace4(0, sd, 0, "fmc_cnt#: %02x%02x%02x%02x", x_fmc_cnt3, x_fmc_cnt2, x_fmc_cnt1, x_fmc_cnt0);
//No. of bytes sent to the host
n_bytes.u32 = _current_byte_count.u32 - n_bytes.u32;
//New LBA for the retry
_fmc_set_start_lb_32(_fmc_get_start_lb_32() + (n_bytes.u32 / 512L));
trace4(0, sd, 0, "read lba:%04X%04X xfer_length:%04X%04X", _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(g_n_lb_this_xfer.u32), _lw(g_n_lb_this_xfer.u32));
//clear and unmask the sd_blk_ovrrun interrupt so that we will be warned if this occurs
irq_control(k_irq_fmc_err_sd_blk_ovrun, kbm_irqctl_clear);
irq_control(k_irq_fmc_err, kbm_irqctl_unmask);
//Check to see if the last two packets have gone out the door
trace4(0, sd, 0, "bufferstat - ramrd_b:%d ramrd_a:%d ramwr_b:%d ramwr_a:%d", (_mcu_register_rd(x_isr0) & kbm_isr0_ramrd_b) ? 1 : 0, (_mcu_register_rd(x_isr0) & kbm_isr0_ramrd_a) ? 1 : 0, (_mcu_register_rd(x_isr0) & kbm_isr0_ramwr_b) ? 1 : 0, (_mcu_register_rd(x_isr0) & kbm_isr0_ramwr_a) ? 1 : 0);
Result = sdc_wait_irq_with_timeout((kbm_isr0_ramrd_a |kbm_isr0_ramrd_b), 2000);
if(Result != k_success)
return Result;
trace4(0, sd, 0, "bufferstat - ramrd_b:%d ramrd_a:%d ramwr_b:%d ramwr_a:%d", (_mcu_register_rd(x_isr0) & kbm_isr0_ramrd_b) ? 1 : 0, (_mcu_register_rd(x_isr0) & kbm_isr0_ramrd_a) ? 1 : 0, (_mcu_register_rd(x_isr0) & kbm_isr0_ramwr_b) ? 1 : 0, (_mcu_register_rd(x_isr0) & kbm_isr0_ramwr_a) ? 1 : 0);
return (k_resume);
}
return (k_success);
}
for(n=0; n<8;n++)
{
_mcu_begin_critical_section();
//Point to buffer A
#ifdef k_dbg_on
dbg_dumpram(_l(addr_word),_h(addr_word), FS_pktsz);
#endif
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[4] + _l(offset));
_mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[4] + _h(offset));
_nop_();
_sd_copy_buf_to_xdata();
//Point to buffer B
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[5]);
_mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[5]);
_nop_();
_sd_copy_xdata_to_buf();
//see what we have copied
#ifdef k_dbg_on
dbg_dumpram(_l(addr_word),_h(addr_word), FS_pktsz);
#endif
//tell how many bytes to xmit
_mcu_register_wr(x_ramrdbc_b2, FS_pktsz);
_mcu_register_wr(x_ramrdbc_b1, FS_pktsz);
//transmit the packet
_mcu_register_clr_bits(x_ep2_ctl, kbm_ep2_ctl_wrtog_valid);
// aim/set ramrd_tog at buffer B so it is ARMED for tx (clrs isr0 ramrd_b bit also)
_mcu_register_set_bits(x_ep2_ctl, kbm_ep2_ctl_rdtog_valid |kbm_ep2_ctl_ramrd_tog);
// _mcu_register_wr(x_isr0, kbm_isr0_ramrd_b);
_nop_();_nop_();_nop_();_nop_();_nop_();
_mcu_end_critical_section();
#ifdef sd_fast_1point1
while(!(_mcu_register_rd(x_isr0) & kbm_isr0_ramrd_b));
#else
Result = sdc_wait_irq_with_timeout(kbm_isr0_ramrd_b, 2000);
if(Result != k_success)
return Result;
#endif
offset = offset + FS_pktsz;
}
#ifdef k_dbg_on
dbg_bufferstat();
#endif
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void dfa_sd_read() reentrant
{
g_cdm0 = 0;
trace1(0, tm, 0, "@%d Start sd_read", g_cdm0);
trace0(0, sd, 3, "+sd_read()");
//Jump to this location on an "Emergency Exit" due to sync_abort or sync_usbreset
if(setjmp(_sd_context))
__thread_return_dfa(k_command_failed);
//clear and unmask the sd_blk_ovrrun interrupt so that we will be warned if this occurs
irq_control(k_irq_fmc_err_sd_blk_ovrun, kbm_irqctl_clear);
irq_control(k_irq_fmc_err, kbm_irqctl_unmask);
if(sie_is_high_speed())
{
trace0(0, sd, 3, "Doing High Speed!");
_sd_data_xfer_cmd = k_sdc_cmd_read_mult_blocks;
//set the callbacks
//_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,sd_read_write_begin_split, fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback);
_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,fmc_dflt_callback, fmc_dflt_callback,fmc_dflt_callback,sd_read_intra_burst,sd_read_end_burst);
} else
{
trace0(0, sd, 3, "Doing Full Speed!");
_sd_data_xfer_cmd = k_sdc_cmd_read_sgl_block;
//set the callbacks
_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback,sd_read_intra_burst,sd_read_end_burst);
}
// 04/28/02 tbh/ds - xdata is not initialized to zero on power up.
// do not depend on the fmc options being cleared to zero at power on.
_fmc_set_options(0);
dfa_lun_read();
trace1(0, tm, 0, "@%d End sd_read", g_cdm0);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result sd_write_copy_data() reentrant;
t_result sd_write_copy_data() reentrant
{
//allocate 64 bytes of xdata space for the temporary holder
uint8 n, Result = 0;
uint16 offset = 0;
g_cdm0 = 0;
trace1(0, sd, 0, "@%d Start write copy data", g_cdm0);
mmu_deallocate(5); // ready to get the next set of data
//mmu_deallocate(4);
_mcu_register_wr(x_isr0, kbm_isr0_ramwr_a);
//_buffer_rx_enable(4);
_mcu_register_wr(x_ep2_ctl, (_mcu_register_rd(x_ep2_ctl) & ~kbm_ep2_ctl_ramwr_tog) |kbm_ep2_ctl_wrtog_valid);
for(n=0; n<8;n++)
{
//get the buffer ready to receive data
#ifdef k_dbg_on
dbg_bufferstat();
#endif
#ifdef sd_fast_1point1
thread_set_timer(2000);
while(!thread_got_sync(kbm_sync_usbrx))
{
if(thread_got_sync(kbm_sync_timer))
{
return k_timeout;
}
}
thread_clr_sync(kbm_sync_usbrx);
#else
Result = sdc_wait_irq_with_timeout(kbm_isr0_ramwr_a, 2000);
if(Result != k_success)
return Result;
#endif
//Start the copying process
trace1(0, tm, 0, "@%d Start copy", g_cdm0);
mcu_begin_critical_section();
//Point to buffer A
#ifdef k_dbg_on
dbg_dumpram(k_pkt_addrlo[4],k_pkt_addrhi[4], FS_pktsz);
#endif
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[4]);
_mcu_register_wr(x_sram_addr_hi,k_pkt_addrhi[4]);
_nop_();
_sd_copy_buf_to_xdata();
//let the next pkt come in
if(n != 7)
{
//mmu_deallocate(4);
_mcu_register_wr(x_isr0, kbm_isr0_ramwr_a);
//_buffer_rx_enable(4);
_mcu_register_wr(x_ep2_ctl, (_mcu_register_rd(x_ep2_ctl) & ~kbm_ep2_ctl_ramwr_tog) |kbm_ep2_ctl_wrtog_valid);
}
//Point to buffer B
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[5] + _l(offset));
_mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[5] + _h(offset));
_nop_();
_sd_copy_xdata_to_buf();
offset = offset + FS_pktsz;
mcu_end_critical_section();
trace1(0, tm, 0, "@%d End copy", g_cdm0);
//see what we have copied
#ifdef k_dbg_on
dbg_dumpram(_l(addr_word),_h(addr_word), FS_pktsz);
#endif
}
trace0(0, sd, 0, "Setting Data Loaded to true");
_sd_data_loaded = k_true;
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result sd_write_begin_burst() reentrant
{
t_result Result = 0;
trace0(0, sd, 3, "sd_write_begin_burst");
if(_sd_data_loaded == k_false)
{
trace0(0, sd, 0, "Data Not Loaded yet..");
Result = sd_write_copy_data();
}
//Now the 512 bytes from Buffer B needs to go to fmdu
//get the buffer B ready to transmit data
#ifdef k_dbg_on
dbg_bufferstat();
#endif
mcu_begin_critical_section();
thread_clr_sync(kbm_sync_usbtx);
_mcu_register_wr(x_isr0, kbm_isr0_ramrd_b);
_mcu_register_wr(x_ramrdbc_b2, _l(512));
_mcu_register_wr(x_ramrdbc_b1, _h(512));
// aim/set ramrd_tog at buffer B so it is ARMED for tx (clrs isr0 ramrd_b bit also)
_mcu_register_set_bits(x_ep2_ctl, kbm_ep2_ctl_rdtog_valid |kbm_ep2_ctl_ramrd_tog);
#ifdef k_dbg_on
dbg_bufferstat();
#endif
// mask it back in to get the irq
_mcu_register_clr_bits(x_imr0, kbm_isr0_ramrd_b);
mcu_end_critical_section();
_mcu_register_wr(x_sdc_stat, kbm_sdc_stat_crd_rdy);
trace1(0, sd, 0, "@%d End write burst", g_cdm0);
_sd_data_loaded = k_false;
return k_success;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result sd_write_end_burst() reentrant
{
t_result Result;
//if this is an aborted transfer get out immediately
if(k_success != g_fmc_rslt)
{
trace2(0, sd, 3, "Aborted transfer ... getting out of here! %d %d",g_fmc_rslt, _fmc_get_result());
return _fmc_get_result();
}
trace1(0, sd, 1, "_sd_data_loaded : %02x",_sd_data_loaded);
//The data has been sent to fmdu.
if((_sd_data_loaded == k_false) && (_mscbot_residue_32() - (uint32)512))
{
trace0(0, sd, 0, "Data Not Loaded yet..");
Result = sd_write_copy_data();
}
trace1(0, sd, 3, "The stat register %02x",_mcu_register_rd(x_sdc_stat));
Result = fmc_wait_blk_irq_with_timeout(g_fmc_timeout);
if(Result == k_success)
if(!(x_sdc_stat & kbm_sdc_stat_crd_rdy))
sdc_wait_status_with_timeout(kbm_sdc_stat_crd_rdy,1000);
return Result;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void dfa_sd_write(void) reentrant
{
//t_result result;
trace0(0, sd, 3, "+sd_write()");
//Jump to this location on an "Emergency Exit" due to sync_abort or sync_usbreset
if(setjmp(_sd_context))
{
trace0(0, sd, 0, "EMERGENCY EXIT!!");
__thread_return_dfa(k_command_failed);
}
//Is the media write protected?
/*if(_sd_write_protected)
{
_lun_data(sensep) = &sense_write_protect;
__thread_return_dfa(k_command_failed)
} */
if(sie_is_high_speed())
{
trace0(0, sd, 3, "Doing High Speed!");
_sd_data_xfer_cmd = k_sdc_cmd_write_mult_blocks;
//set the callbacks
_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,sd_read_write_begin_split, fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback);
} else
{
trace0(0, sd, 3, "Doing Full Speed!");
_sd_data_xfer_cmd = k_sdc_cmd_write_mult_blocks;
//set the callbacks
_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,sd_read_write_begin_split, fmc_dflt_callback,sd_write_begin_burst,fmc_dflt_callback, sd_write_end_burst);
}
// 04/28/02 tbh/ds - xdata is not initialized to zero on power up.
// do not depend on the fmc options being cleared to zero at power on.
_fmc_set_options(0);
dfa_lun_write();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void dfa_sd_verify(void) reentrant
{
trace0(0, sd, 0, "+sd_verify()");
//Jump to this location on an "Emergency Exit" due to sync_abort or sync_usbreset
if(setjmp(_sd_context))
thread_return_dfa(k_command_failed);
if(sie_is_high_speed())
{
trace0(0, sd, 0, "Doing High Speed!");
_sd_data_xfer_cmd = k_sdc_cmd_write_mult_blocks;
//set the callbacks
_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,sd_read_write_begin_split, fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback,fmc_dflt_callback);
} else
{
trace0(0, sd, 0, "Doing Full Speed!");
_sd_data_xfer_cmd = k_sdc_cmd_write_mult_blocks;
//set the callbacks
_fmc_set_callback(sd_read_write_begin_xfer,sd_read_write_end_xfer,sd_read_write_begin_split, fmc_dflt_callback, sd_write_begin_burst,fmc_dflt_callback,sd_write_end_burst);
}
// 04/28/02 tbh/ds - xdata is not initialized to zero on power up.
// do not depend on the fmc options being cleared to zero at power on.
_fmc_set_options(0);
dfa_lun_verify();
}
//---eof------------------------------------------------------------------------