📄 usim_drv.c
字号:
}
else
{ // command complete
dbg_print("command complete!!\r\n");
usim_dcb.rx_chain = KAL_FALSE;
usim_dcb.retry = 0;
usim_dcb.main_state = MAIN_CMD_READY_STATE;
}
}
else if(USIM_IS_RBLOCK(pcb))
{ // R-block
dbg_print("received a R-block\r\n");
if(usim_dcb.header_tx[T1_PCB_INDEX]== RESYNC_REQ)
{
// must receive a S RESP not any other block
dbg_print("(invalid block) must receive a S RESP not any other block \r\n");
return KAL_FALSE;
}
if(len)
{
dbg_print("(invalid block) R block of len = %d \r\n", len);
return KAL_FALSE;
}
if(usim_dcb.tx_chain && (pcb & PCB_R_STATUS) == 0)
{ // receive a err free R block
if(((pcb & PCB_R_SEQ)<<2) == usim_dcb.ns )
{ // send next chaining block
if(usim_dcb.abort == KAL_TRUE)
{
usim_dcb.main_state = MAIN_CMD_READY_STATE;
}
else if(usim_dcb.tx_size != 0)
{
// normal chaining case
usim_dcb.retry = 0;
usim_dcb.tx_size -= usim_dcb.ifsc;
usim_dcb.tx_index += usim_dcb.ifsc;
*adrs =(kal_uint32)(usim_dcb.tx_buf+usim_dcb.tx_index);
if(usim_dcb.tx_size <= usim_dcb.ifsc)
{
pcb = 0;
len = usim_dcb.tx_size;
usim_dcb.cmd_state = I_BLOCK_M0_TX;
}
else // txSize > IFSC
{
pcb = PCB_I_M;
len = usim_dcb.ifsc;
usim_dcb.cmd_state = I_BLOCK_M1_TX;
}
if(usim_dcb.ns)
pcb |= PCB_I_SEQ;
usim_dcb.header_tx[T1_PCB_INDEX] = pcb;
usim_dcb.header_tx[T1_LEN_INDEX] = len;
usim_dcb.header_tx_bak[T1_PCB_INDEX] = pcb;
usim_dcb.header_tx_bak[T1_LEN_INDEX] = len;
USIM_INV_N(usim_dcb.ns);
}
}
else
{ // sending the previous I block again
usim_dcb.retry++;
usim_dcb.cmd_state = usim_dcb.cmd_state_bak;
usim_dcb.header_tx[T1_PCB_INDEX] = usim_dcb.header_tx_bak[T1_PCB_INDEX];
usim_dcb.header_tx[T1_LEN_INDEX] = usim_dcb.header_tx_bak[T1_LEN_INDEX];
}
}
else
{
// error handling R-Block received
if((pcb & PCB_R_SEQ)<<2 != (usim_dcb.ns) )
{ // previous sending sequence
usim_dcb.retry++;
usim_dcb.cmd_state = usim_dcb.cmd_state_bak;
usim_dcb.header_tx[T1_PCB_INDEX] = usim_dcb.header_tx_bak[T1_PCB_INDEX];
usim_dcb.header_tx[T1_LEN_INDEX] = usim_dcb.header_tx_bak[T1_LEN_INDEX];
}
else
{
// next sending sequence
// send the previous R-block again
usim_dcb.retry = 0;
return KAL_FALSE;
}
}
}
else if(USIM_IS_SBLOCK(pcb))
{ // S-block(REQ)
dbg_print("receive S-block(%x)\r\n",pcb);
if(USIM_IS_RESP(pcb))
{ // response (only resync response block will be received.)
dbg_print("receive RESP block!\r\n");
if(pcb == RESYNC_RESP && usim_dcb.header_tx[T1_PCB_INDEX]== RESYNC_REQ )
{
if(len != 0)
{
dbg_print("Invalid len of RESYNC");
return KAL_FALSE;
}
// resync complete (the card is reset to the initial state)
usim_dcb.main_state = MAIN_CMD_READY_STATE;
usim_dcb.ns = 0;
usim_dcb.nr = 0;
usim_dcb.resync = KAL_TRUE;
usim_dcb.retry = 0;
// usim_dcb.ifsc = USIM_IFSC_DEFAULT;
}
else
{
dbg_print("receive a error S RESP,[%x]\r\n", pcb);
return KAL_FALSE;
}
}
else
{ // receiving a S-block of request
if(usim_dcb.header_tx[T1_PCB_INDEX]== RESYNC_REQ)
{
// must receive a S RESP not any other block
dbg_print("(invalid block) must receive a S RESP not any other block \r\n");
return KAL_FALSE;
}
usim_dcb.cmd_state = S_BlOCK_RESP_TX;
usim_dcb.header_tx[T1_PCB_INDEX]= pcb|PCB_S_RESP;
usim_dcb.header_tx[T1_LEN_INDEX]= len;
if(len)
{
usim_dcb.header_tx[T1_INF_INDEX] = usim_dcb.header_rx[T1_INF_INDEX];
}
switch(pcb)
{
case RESYNC_REQ:
dbg_print("(ERR) receive RESYNC_REQ\r\n");
return KAL_FALSE;
break;
case IFS_REQ:
dbg_print("receive IFS_REQ\r\n");
if(len != 1)
return KAL_FALSE;
usim_dcb.ifsc = usim_dcb.header_rx[T1_INF_INDEX];
break;
case ABORT_REQ:
dbg_print("receive ABORT_REQ\r\n");
if(len != 0)
return KAL_FALSE;
usim_dcb.retry = 0;
usim_dcb.abort = KAL_TRUE;
break;
case WTX_REQ:
if(len != 1)
return KAL_FALSE;
usim_dcb.retry = 0;
dbg_print("receive WTX_REQ\r\n");
// re-start the BWT( according to the spec, the timer should be restart after
// the WTX response has been sent.
usim_dcb.wtx = KAL_TRUE;
usim_dcb.wtx_m = usim_dcb.header_rx[T1_INF_INDEX];;
break;
default:
return KAL_FALSE;
}
}
}
else
{
dbg_print("Invalid PCB \r\n");
return KAL_FALSE;
}
return KAL_TRUE;
}
/*************************************************************************
* FUNCTION
* usim_err_handler
*
* DESCRIPTION
* 1. send R block to UICC to indicate the previous block is error at previous two retry.
* 2. send S(RESYN) to UICC to recover the errors.
* 3. deactivate the UICC
*
* PARAMETERS
*
* RETURNS
*
* GLOBALS AFFECTED
* usim_dcb.retry
*
*************************************************************************/
static void usim_err_handler(void)
{
// send R block
usim_dcb.retry++;
dbg_print("usim_err_handler %d",usim_dcb.retry);
USIM_CLR_FIFO();
if(usim_dcb.retry < 3)
{
dbg_print("send R block!\r\n");
{
if(usim_dcb.ev_status == USIM_RX_INVALID)
{
USIM_MAKE_R_BLOCK(PCB_R_STATUS_EDC_ERR);
}
else
{
USIM_MAKE_R_BLOCK(PCB_R_STATUS_OTHER_ERR);
}
}
}
else if(usim_dcb.retry < 6)
{
// next level error handling => resync
dbg_print("send RESYNC REQ !\r\n");
USIM_MAKE_S_RESYNC();
}
else
{
// deactivate
usim_deactivation();
}
}
/*************************************************************************
* FUNCTION
* usim_send_i_block
*
* DESCRIPTION
* 1. send I block to UICC with length of ifsc including case 1~4.
*
* PARAMETERS
* 1. txData: tx buffer containing command header optional with tx data.
* 2. txSize: length of the tx data
* 3. rxData: rx buffer (must inluding two extra one for sw1 and sw2)
* 4. rxSize: length of the rx data except sw1|sw2
*
* RETURNS
* status bytes(SW1|SW2), 0 means a physical error.
*
* GLOBALS AFFECTED
* usim_dcb
*
*************************************************************************/
static sim_status usim_send_i_block(kal_uint8 *txData,kal_uint32 *txSize,kal_uint8 *rxData, kal_uint32 *rxSize)
{
kal_uint8 pcb, len;
kal_uint32 count,adrs;
usim_status_enum status;
kal_uint16 sw;
dbg_print("\r\n\r\n @@@@ usim_send_i_block @@@@\r\n");
DRVPDN_Disable(DRVPDN_CON1,DRVPDN_CON1_SIM,PDN_SIM);
if(usim_dcb.clock_stop_en == KAL_TRUE)
{
if(usim_dcb.main_state == CLK_STOPPING_STATE)
{
usim_set_timeout(0);
usim_dcb.main_state = MAIN_CMD_READY_STATE;
}
else if(usim_dcb.main_state == CLK_STOPPED_STATE)
{
DRV_Reg(SIM_CTRL) &= ~SIM_CTRL_HALT;
usim_set_timeout(usim_dcb.etu_of_700);
DRV_WriteReg(SIM_IRQEN, SIM_IRQEN_TOUT);
USIM_WAIT_EVENT();
}
}
do
{
status = USIM_NO_ERROR;
usim_dcb.tx_index = 0;
usim_dcb.rx_index = 0;
usim_dcb.tx_buf = txData;
if(*rxSize == 0)
usim_dcb.rx_buf = usim_dcb.sw;
else
usim_dcb.rx_buf = rxData;
usim_dcb.tx_size = *txSize;
usim_dcb.rx_size = *rxSize+2; // include SW1, SW2
usim_dcb.retry = 0;
usim_dcb.abort = KAL_FALSE;
usim_dcb.resync = KAL_FALSE;
usim_dcb.rx_chain = KAL_FALSE;
count = *txSize;
adrs =(kal_uint32)usim_dcb.tx_buf;
if(count <= usim_dcb.ifsc)
{
pcb = 0;
len = count;
usim_dcb.tx_chain = KAL_FALSE;
usim_dcb.cmd_state = I_BLOCK_M0_TX;
}
else // txSize > IFSC
{
pcb = PCB_I_M;
len = usim_dcb.ifsc;
usim_dcb.tx_chain = KAL_TRUE;
usim_dcb.cmd_state = I_BLOCK_M1_TX;
}
if(usim_dcb.ns)
pcb |= PCB_I_SEQ;
usim_dcb.cmd_state_bak = usim_dcb.cmd_state;
usim_dcb.header_tx[T1_NAD_INDEX] = USIM_NAD_DEFAULT;
usim_dcb.header_tx[T1_PCB_INDEX] = pcb;
usim_dcb.header_tx_bak[T1_PCB_INDEX] = pcb;
usim_dcb.header_tx[T1_LEN_INDEX] = len;
usim_dcb.header_tx_bak[T1_LEN_INDEX] = len;
USIM_INV_N(usim_dcb.ns);
while(1)
{
usim_send_block((kal_uint8*)adrs);
USIM_WAIT_EVENT();
if(usim_dcb.ev_status == USIM_NO_ERROR)
{ // a complete block is received
if(usim_rx_block_handler(&adrs)== KAL_FALSE)
usim_err_handler();
}
else
{
usim_err_handler();
}
if(usim_dcb.main_state == MAIN_CMD_READY_STATE)
{
// command complete
*rxSize = usim_dcb.rx_index;
break;
}
}
if(usim_dcb.abort == KAL_TRUE)
{
status = USIM_DATA_ABORT;
break;
}
if(usim_dcb.main_state == DEACTIVATION_STATE)
{
status = USIM_DEACTIVATED;
break;
}
}while(usim_dcb.resync == KAL_TRUE);
if(usim_dcb.clock_stop_en == KAL_TRUE)
{
usim_dcb.main_state = CLK_STOPPING_STATE;
usim_set_timeout(usim_dcb.etu_of_1860);
DRV_WriteReg(SIM_IRQEN, SIM_IRQEN_TOUT);
#if defined(USIM_DEBUG)
start = get_current_time();
#endif
}
usim_dcb.status = status;
if(status != USIM_NO_ERROR)
return STATUS_FAIL;
// the *rxsize include the sw1 and sw1, the upper layer should prepare it.
*rxSize -= 2;
if(*rxSize == 0)
return (kal_uint16)((usim_dcb.sw[0]<<8)|(usim_dcb.sw[1]));
sw = (rxData[*rxSize]<<8)|(rxData[*rxSize+1]);
return sw;
}
/*************************************************************************
* FUNCTION
* usim_update_sim_to_ready
*
* DESCRIPTION
* 1. update the ATR informations from usim_dcb into SimCard
* to make sim(t=0) driver work..
*
* PARAMETERS
*
* RETURNS
*
* GLOBALS AFFECTED
* SimCard
* TOUTValue
*
*************************************************************************/
void static usim_update_sim_to_ready(void)
{
extern kal_uint32 TOUTValue;
SimCard.app_proto = usim_dcb.app_proto;
SimCard.State = SIM_PROCESSCMD;
SimCard.Data_format = usim_dcb.dir;
if(usim_dcb.power == CLASS_B_30V)
SimCard.Power = SIM_30V;
else if(usim_dcb.power == CLASS_C_18V)
SimCard.Power = SIM_18V;
SimCard.SIM_ENV = usim_dcb.sim_env;
SimCard.Speed = usim_dcb.speed;
SimCard.clkStop = usim_dcb.clock_stop_en;
if(usim_dcb.clock_stop_type == CLOCK_STOP_HIGH)
SimCard.clkStopLevel = KAL_TRUE;
else if(usim_dcb.clock_stop_type == CLOCK_STOP_LOW)
SimCard.clkStopLevel = KAL_FALSE;
SimCard.sim_card_speed = usim_dcb.card_speed;
TOUTValue = usim_dcb.WWT>>2;
}
/*************************************************************************
* FUNCTION
* L1usim_Init
*
* DESCRIPTION
* 1. It is the initialization function of usim driver
* 2. It shall be called only once.
* 3. It gets the customization data of borad-supported voltage.
* 4. It initialize the structure of usim control block .
* 5. It get a GPT handler, a dma port,and register lisr, hisr, a event groug
*
* PARAMETERS
None
* RETURNS
None
* GLOBALS AFFECTED
* usim_dcb
*
*************************************************************************/
void L1usim_Init(void)
{
if(usim_dcb.warm_rst == KAL_FALSE)
{
usim_dcb.sim_env = SIM_GetCurrentEnv();
usim_dcb.dir = USIM_DIRECT;
usim_dcb.speed = SPEED_372;
usim_dcb.clock_stop_en = KAL_FALSE;
usim_dcb.clock_stop_type = CLOCK_STOP_UNKONW;
usim_dcb.phy_proto = T1_PROTOCOL;
usim_dcb.warm_rst = KAL_FALSE;
usim_dcb.rx_size = 0;
usim_dcb.rx_buf = NULL;
usim_dcb.tx_size = 0;
usim_dcb.tx_buf = NULL;
usim_dcb.Fi = FI_DEFAULT;
usim_dcb.Di = DI_DEFAULT;
usim_dcb.header_tx[0] = NAD;
usim_dcb.ts_hsk_en = KAL_TRUE;
usim_dcb.WWT = INIT_WWT_T0;
usim_dcb.etu_of_1860 = (1860/32);
usim_dcb.etu_of_700 = (700/32);
usim_dcb.present = KAL_TRUE;
// note: MT6218B half channel can't work, use full channel insteadly.
#if !defined(MT6218B) && !defined(MT6218)
if(usim_dcb.dma_port == 0)
usim_dcb.dma_port = DMA_GetChannel(DMA_SIM);
usim_dcb.dma_menu.TMOD.burst_mode = KAL_FALSE;
usim_dcb.dma_menu.master = DMA_SIM;
usim_dcb.dma_menu.addr = NULL;
usim_dcb.dma_input.type = DMA_HWTX;
usim_dcb.dma_input.size = DMA_BYTE;
usim_dcb.dma_input.callback = NULL;
usim_dcb.dma_input.menu = &usim_dcb.dma_menu;
#endif
if(usim_dcb.event == NULL)
usim_dcb.event = kal_create_event_group("USIM_EV");
if(usim_dcb.hisr == NULL)
usim_dcb.hisr = kal_create_hisr("USIM_HISR",1,512,usim_hisr,NULL);
if(usim_dcb.gpt_handle == NULL)
GPTI_GetHandle(&usim_dcb.gpt_handle);
IRQSensitivity(IRQ_SIM_CODE,LEVEL_SENSITIVE);
IRQUnmask(IRQ_SIM_CODE);
}
// reset these value no matter cold or warm reset
usim_dcb.main_state = ACTIVATION_STATE;
usim_dcb.ifsc = USIM_IFSC_DEFAULT;
usim_dcb.ifsd = USIM_IFSD_DEFAULT;
usim_dcb.ns = 0;
usim_dcb.nr = 0;
IRQ_Register_LISR(IRQ_SIM_CODE, usim_lisr,"USIM_Lisr");
}
/*************************************************************************
* FUNCTION
* L1sim_Reset
*
* DESCRIPTION
* 1. Reset the sim card and parse the ATR and perform the PTS(optional) and
enter the command ready mode
* 2. First time it is a cold reset, second it's a warm reset
* 3. If the ExpectVolt equal to the current volt, perform a warm reset.
Otherwise perform a cold reset.
* 4. Finally, S-block of IFS request is sent the UICC to configure the IFSD
*
* PARAMETERS
1. ExpectVolt: application layer give a expected power class
* RETURNS
* USIM_VOLT_NOT_SUPPORT: Valid TS is received
* KAL_FALSE: Valid TS is not received, card is not present or not supported
*
* GLOBALS AFFECTED
* usim_dcb
*
*************************************************************************/
usim_status_enum L1usim_Reset(usim_power_enum ExpectVolt, usim_power_enum *ResultVolt)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -