跳到主要内容

SCR - 智能卡读取器

模块介绍

智能卡读取器(SCR)是一种通信控制器,可在系统和智能卡之间传输数据。控制器可以执行完整的智能卡会话,包括停用卡激活卡,冷/热重置,重置应答(ATR)响应接收,数据传输等。

模块配置

Kernel Setup --->
Drivers Setup --->
SoC HAL Drivers --->
smartcard devices --->
[*] enable smartcard driver

源码结构

rtos-hal/
|--hal/source/smartcard/scr_hal.c // hal层接口代码

模块接口说明

头文件

#include <sunxi_hal_scr.h>

SCR 命令枚举

enum scr_cmd {
SCR_IOCGSTATUS = 0,
SCR_IOCRESET,
SCR_IOCGATR,
SCR_IOCGPARA,
SCR_IOCSPARA,
SCR_IOCGATRPARA,
SCR_IOCGPPSPARA,
SCR_IOCWRDATA,
};

SCR ATA 数据结构体

struct scr_atr {
unsigned char atr_len;
unsigned char atr_data[MAX_ATR_LEN];
};

SMARTCARD 初始化接口

SMARTCARD 模块初始化,主要初始化采样率、通道选择及注册中断等

hal_scr_status_t hal_scr_init(void);

参数:

返回值

  • 0:成功
  • 负数:失败

SMARTCARD 测试接口

SMARTCARD 模块功能测试

hal_scr_test(enum scr_cmd cmd, void *arg)

参数:

  • cmd:命令
  • arg:参数

返回值

  • 0:成功
  • 负数:失败

#include <stdio.h>
#include <stdlib.h>
#include <interrupt.h>
#include <irqs.h>
#include <string.h>
#include <console.h>
#include <param.h>
#include <hal_osal.h>
#include <hal_timer.h>
#include <hal_atomic.h>
#include "hal_clk.h"
#include <hal_gpio.h>
#include <hal_reset.h>

#include <sunxi_hal_scr.h>

#include "scr_test.h"

#define SCR_TEST_INFO printf
#define SCR_TEST_DBG printf
#define get_wvalue readl
#define APB2CLK 24000000

const unsigned int SCR_REG_DEFAULT[] = {12 //reg Count
,0x00000000 ,0x000 ,0x01ff0f07 //reg 0: (default, addr, mask)
,0x00000000 ,0x004 ,0x00ff1e1f
,0x00000000 ,0x008 ,0x00ff1e1f
,0x00000101 ,0x00c ,0x00000707
,0x00000000 ,0x010 ,0x1f1f1f1f //0x1f001f1f //
,0x00000000 ,0x014 ,0x000000ff
,0x00000000 ,0x018 ,0xffffffff
,0x00000000 ,0x01c ,0x00ffffff
,0x00000000 ,0x020 ,0xffff00ff
,0x00000000 ,0x030 ,0x000000ff
,0x00000000 ,0x03c ,0xffffffff
,0x000003ff ,0x040 ,0xffffffff
};

const unsigned int SCR_REG_RW[] = {12 //reg Count
,0x01 //Byte|Hword|Word
,0x00000000 ,0x000 ,0x01ff0007 //reg 0: (default, addr, mask)
,0x00000000 ,0x004 ,0x00ff1e1f
,0x00000000 ,0x008 ,0x00000000
,0x00000101 ,0x00c ,0x00000000
,0x00000000 ,0x010 ,0x1f1f0000 //0x1f000000 //
,0x00000000 ,0x014 ,0x000000ff
,0x00000000 ,0x018 ,0xffffffff
,0x00000000 ,0x01c ,0x00ffffff
,0x00000000 ,0x020 ,0xffff00ff
,0x00000000 ,0x030 ,0x000000fd
,0x00000000 ,0x03c ,0x00000000
,0x000003ff ,0x040 ,0xffffffff
};

uint8_t ic_card_atr[SMART_CARD_NUM][30] = {
{ 7, 0x3b, 0x93, 0x11, 0x00, 0x00, 0x40, 0x41 }, //莱西有线
{ 18, 0x3b, 0x7d, 0x94, 0x00, 0x00, 0x57, 0x44, 0x53, 0x67, 0x96, 0x86,
0x93, 0x03, 0x9d, 0xf7, 0x10, 0x00, 0x9d }, //神州大众卡1
{ 15, 0x3b, 0xb9, 0x94, 0x00, 0x40, 0x14, 0x47, 0x47, 0x33, 0x53, 0x30,
0x35, 0x41, 0x53, 0x30 }, //神州大众卡2
{ 17, 0x3b, 0x9d, 0x95, 0x00, 0x13, 0x61, 0x40, 0x36, 0x13, 0x85, 0xe9,
0x44, 0x34, 0x8f, 0x78, 0x8f, 0x4a }, //数字电视卡1
{ 17, 0x3b, 0x9d, 0x95, 0x00, 0x13, 0x61, 0x40, 0x36, 0x13, 0x85, 0xe9,
0x44, 0x34, 0xf3, 0x78, 0x8f, 0x4a }, //数字电视卡2
{
22, 0x3b, 0x9f, 0x95, 0x80, 0x1f, 0xc3, 0x80,
0x31, 0xe0, 0x73, 0xfe, 0x21, 0x13, 0x57, 0x86,
0x81, 0x02, 0x86, 0x98, 0x44, 0x18, 0xa8 }, //电信4G卡
{ 20, 0x3b, 0xfb, 0x94, 0x00, 0x00, 0x80, 0x1f, 0x83, 0x80, 0x65,
0x92, 0x10, 0x26, 0x86, 0x53, 0x83, 0x00, 0x90, 0x00, 0xf4 }, //联通卡
{ 16, 0x3b, 0x7b, 0x94, 0x00, 0x00, 0x97, 0x88, 0x84, 0x86, 0x60, 0xa0,
0x04, 0x01, 0x00, 0x04, 0x00 }, //移动卡
{ 20, 0x3b, 0x7f, 0x12, 0x00, 0x00, 0x44, 0x56, 0x4e, 0x20, 0x54,
0x45, 0x53, 0x54, 0x20, 0x43, 0x41, 0x52, 0x44, 0x76, 0x31 } // digital
// TV卡
};

uint8_t ic_card_send_cmd[SMART_CARD_NUM][30] = {
{ 5, 0xe5, 0x04, 0x00, 0x00, 0x04 }, //莱西有线
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 7, 0xA0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 }, //移动卡
{ 0 }
};

uint8_t ic_card_rev_data[SMART_CARD_NUM][30] = {
{ 7, 0x04, 0x4d, 0x33, 0x4f, 0x4b, 0x90, 0x00 }, //莱西有线
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 3, 0xa4, 0x9f, 0x1b }, //移动卡
{ 0 }
};

scr_struct scr;
scr_fsm_record scr_fsm;
scatr_struct scatr;
upps_struct pps;

extern scr_test_stage stage;
static int state_dly = 0x0;

#define SCR_SIM_DBG(x) pattern_mod_goto(0x2, x)

void scr_ccu_clk_gate_on(u32 sel)
{
int ret;
ret = readl(0x4003c004);
hal_write_reg32(0x4003c004, 0x4000000 | ret);
}

void scr_ccu_clk_gate_off(u32 sel)
{
int ret;
ret = readl(0x4003c004);
hal_write_reg32(0x4003c004, 0xfbffffff & ret);
}

void scr_module_rst_on(u32 sel)
{
int ret;
ret = readl(0x4003c00c);
hal_write_reg32(0x4003c00c, 0x4000000 | ret);
}

void scr_module_rst_off(u32 sel)
{
int ret;
ret = readl(0x4003c00c);
hal_write_reg32(0x4003c00c, 0xfbffffff & ret);
}

void scr_module_rst(u32 sel)
{
scr_module_rst_off(sel);
udelay(300);
scr_module_rst_on(sel);
udelay(300);
}

void scr_pio_setup(void)
{
int ret;
ret = hal_gpio_pinmux_set_function(GPIOA(14), 5);
if (ret) {
printf("scr pin set function failed\n");
return -1;
}
}

/* Configure the CCMU Clock & De-assert Reset & Gating & GPIO configure */
void scr_system_setup(u32 sel)
{
scr_module_rst_off(sel);
scr_ccu_clk_gate_off(sel);
udelay(300);
scr_ccu_clk_gate_on(sel); /*enable APB clock*/
scr_module_rst_on(sel);
scr_pio_setup(); /*IO configure*/
}

uint32_t
scr_reg_test(void) // registers default values cheak and read write check
{
uint32_t temp;

scr_module_rst(SCR_NO);
SCR_TEST_INFO("SCR Register Test Pass!!\n");
return 1;
}

static hal_irqreturn_t scr0_irq_handler(void* dev)
{
scr_handler_irq(&scr);

return 0;
}

void reg_scr0_irq_handler(void)
{
hal_request_irq(scr.irq_no, scr0_irq_handler, "scr0", &scr);
hal_enable_irq(scr.irq_no);
}

void scr_params_init(void)
{
scr.reg_base = 0x40045400;

scr.irq_no = 69; //中断号
scr.csr_config = CSR_CONFIG_DETPOL | CSR_CONFIG_T | CSR_CONFIG_ATRSTFLUSH | CSR_CONFIG_TSRXEN | CSR_CONFIG_CLKSTPPOL | CSR_CONFIG_PECRXE | CSR_CONFIG_MSBF | CSR_CONFIG_DPOL;

scr.inten_bm = 0xffffffff; // Enbale all the interrupts
scr.txfifo_thh = SCR_FIFO_DEPTH / 2; // set the txfifo trigger level as half full
scr.rxfifo_thh = SCR_FIFO_DEPTH / 2; // set the rxfifo trigger level as half full
scr.tx_repeat = 0x3; // iso7816中规定对于存在争议的字符,最多只能重发3次
scr.rx_repeat = 0x3; // iso7816中规定对于存在争议的字符,最多只能重发3次

scr.scclk_div = (APB2CLK / (2 * SCR_CLK_FRQ)) - 1; // PCLK/12, <175, && SCCLK >= 1M && =<4M
scr.baud_div = (scr.scclk_div + 1) * 372 - 1; // ETU = 372*SCCLK

scr.act_time = 1; // 1*256 clock cycle
scr.rst_time = 1; // 1*256 clock cycle
scr.atr_time = (35000 >> 8); // 400~40000 冷复位和热复位时,在RST拉高后,IO要作出ATR的时间限制
scr.guard_time = 2; //=2*ETUs /* GT = 12etu + R * N/f --- Default extra
// guard time is 0 */
scr.chlimit_time = 9600; // 1024*(10+scr.guard_time); //1K Characters
scr.debounce_time = 0xfffff; // insert detect debounce time
}

volatile u32 card_name = 0;
volatile u32 scr_ret = 0;
uint32_t scr_test_process(pscr_struct pscr)
{
uint8_t atr_temp[30];
uint8_t rsp_temp[30];
u32 i = 0;
u32 j = 0;
uint8_t atr_cmp = 0;

switch (stage) {
case sts_wait_connect:
if (scr.detected) /*if detect card, ACT the card*/
{
state_dly++;
if (state_dly >= 50) {
msleep(10);
scr_start_activation(&scr); /* Activation */
stage = sts_wait_act;
state_dly = 0;
}
} else {
state_dly = 0;
}
break;
case sts_wait_act:
if (scr.activated) {
stage = sts_wait_atr;
}
break;
case sts_wait_atr:
if (scr.atr_resp != SCR_ATR_RESP_INVALID) {
if (scr.atr_resp == SCR_ATR_RESP_OK) /*ATR response is 有效的*/
{
uint32_t i = 0;
SCR_TEST_DBG("ATR = ");
for (i = 0; i < scr.rxbuf.wptr; i++) {
SCR_TEST_DBG("0x%02x ", *((uint8_t*)(scr.rxbuf.buffer + i)));
atr_temp[i] = *((uint8_t*)(scr.rxbuf.buffer + i));
}
SCR_TEST_DBG(" \n");
scr.rxbuf.rptr = scr.rxbuf.wptr;
smartcard_atr_decode(&scatr, (uint8_t*)scr.rxbuf.buffer, &pps, 1);

scr_buffer_flush(&scr.rxbuf); // clean rxbuffer
stage = sts_start_pps;

for (i = 0; i < SMART_CARD_NUM; i++) {
u32 atr_length = ic_card_atr[i][0];
for (j = 0; j < atr_length; j++) {
if (atr_temp[j] != ic_card_atr[i][j + 1]) {
break;
}
}
if (j == atr_length) {
card_name = i;
atr_cmp = 1;
break;
} else {
atr_cmp = 0;
}
}

if (atr_cmp) {
printf("crad_name = %d\n", card_name);
printf("ATR Function PASS!!\n");
} else {
printf("ATR Function FAIL!!\n");
}
} else {
stage = sts_start_deact;
}
}
break;
case sts_start_pps: /* Protocol and parameters selection */
pscr->chto_flag = 0;
scr_buffer_flush(&scr.rxbuf);

scr_write_fifo(&scr, pps.ppss);
printf("ppss:%x \n", pps.ppss);
scr_write_fifo(&scr, pps.pps0);
printf("pps0:%x \n", pps.pps0);
if (pps.pps0 & (0x1 << 4)) {
scr_write_fifo(&scr, pps.pps1);
printf("pps1:%x \n", pps.pps1);
}
if (pps.pps0 & (0x1 << 5)) {
scr_write_fifo(&scr, pps.pps2);
printf("pps2:%x \n", pps.pps2);
}
if (pps.pps0 & (0x1 << 6)) {
scr_write_fifo(&scr, pps.pps3);
printf("pps3:%x \n", pps.pps3);
}
scr_write_fifo(&scr, pps.pck);
printf("pck:%x \n", pps.pck);

stage = sts_wait_pps_resp;
break;
case sts_wait_pps_resp: // pps交换成功的最普通的情况就是:卡设备的pps请求和ic卡的pps应答的内容完全一样
if (pscr->chto_flag) // Wait Data Timeout/*time is too long, time is
// out*/
{
if (scr_buffer_is_empty(&scr.rxbuf)) // RX Buffer, No Response
{
SCR_TEST_INFO("No PPS Response!!\n");
stage = sts_warm_reset;
} else {
uint8_t data = scr_dump_buffer(&scr.rxbuf); // read ppss
printf("ppss:%x \n", data);
if (data != pps.ppss) // check ppss
{
SCR_TEST_INFO("PPS Resp Start Error: 0x%x !!\n", data);
break;
}
if (scr_buffer_is_empty(&scr.rxbuf)) // no pps0
{
SCR_TEST_INFO("PPS Resp Too Short 1\n");
break;
}
data = scr_dump_buffer(&scr.rxbuf); // read pps0
printf("pps0:%x \n", data);
if (data != pps.pps0) // check pps0
{
SCR_TEST_INFO("PPS Resp PPS0 Error: 0x%x vs 0x%x !!\n", pps.pps0,
data);
break;
}
if (pps.pps0 & (0x1 << 4)) //根据pps0的值,有pps1
{
if (scr_buffer_is_empty(&scr.rxbuf)) //收不到pps1
{
SCR_TEST_INFO("PPS Resp Too Short 2\n");
break;
}
data = scr_dump_buffer(&scr.rxbuf); //读取pps1
printf("pps1:%x \n", data);
if (data != pps.pps1) //检测pps1
{
SCR_TEST_INFO("PPS Resp PPS1 Error: 0x%x vs 0x%x !!\n", pps.pps1,
data);
break;
}
}
if (pps.pps0 & (0x1 << 5)) //根据pps0的值,有pps2
{
if (scr_buffer_is_empty(&scr.rxbuf)) //收不到pps2
{
SCR_TEST_INFO("PPS Resp Too Short 3\n");
break;
}
data = scr_dump_buffer(&scr.rxbuf); //读取pps2
printf("pps2:%x \n", data);
if (data != pps.pps2) //检测pps2
{
SCR_TEST_INFO("PPS Resp PPS2 Error: 0x%x vs 0x%x !!\n", pps.pps2,
data);
break;
}
}
if (pps.pps0 & (0x1 << 6)) //根据pps0的值,有pps3
{
if (scr_buffer_is_empty(&scr.rxbuf)) //收不到pps3
{
SCR_TEST_INFO("PPS Resp Too Short 4\n");
break;
}
data = scr_dump_buffer(&scr.rxbuf); //读取pps3
printf("pps3:%x \n", data);
if (data != pps.pps3) //检测pps3
{
SCR_TEST_INFO("PPS Resp PPS3 Error: 0x%x vs 0x%x !!\n", pps.pps3,
data);
break;
}
}
if (scr_buffer_is_empty(&scr.rxbuf)) //收不到pck
{
SCR_TEST_INFO("PPS Resp Too Short 5\n");
break;
}
data = scr_dump_buffer(&scr.rxbuf); //读取pck
printf("pck:%x \n", data);
if (data != pps.pck) //检测pck
{
SCR_TEST_INFO("PPS Resp PCK Error: 0x%x vs 0x%x !!\n", pps.pck, data);
break;
}

scr_buffer_flush(&scr.rxbuf);
stage = sts_send_cmd;

SCR_TEST_INFO(
"PPS Response OK!!\n"); //如果上述if中都没有break出来,则表示pps交换成功

scr.baud_div = (scr.scclk_div + 1) * (scatr.F) / (scatr.D) - 1;
scr_set_baud_divisor(&scr, pscr->baud_div);
}
}
break;

case sts_warm_reset:
scr.atr_resp = SCR_ATR_RESP_INVALID;
scr_start_warmreset(&scr);
stage = sts_wait_atr_again;
break;

case sts_wait_atr_again:
if (scr.atr_resp != SCR_ATR_RESP_INVALID) {
if (scr.atr_resp == SCR_ATR_RESP_OK) /*ATR response is 有效的*/
{
uint32_t i = 0;
SCR_TEST_DBG("ATR : ");
for (i = 0; i < scr.rxbuf.wptr; i++) {
SCR_TEST_DBG("0x%02x ", *((uint8_t*)(scr.rxbuf.buffer + i)));
atr_temp[i] = *((uint8_t*)(scr.rxbuf.buffer + i));
}
SCR_TEST_DBG(" \n");
scr.rxbuf.rptr = scr.rxbuf.wptr;
smartcard_atr_decode(&scatr, (uint8_t*)scr.rxbuf.buffer, &pps, 1);

for (i = 0; i < SMART_CARD_NUM; i++) {
u32 atr_length = ic_card_atr[i][0];
for (j = 0; j < atr_length; j++) {
if (atr_temp[j] != ic_card_atr[i][j + 1]) {
break;
}
}
if (j == atr_length) {
card_name = i;
atr_cmp = 1;
break;
} else {
atr_cmp = 0;
}
}

if (atr_cmp) {
printf("crad_name = %d\n", card_name);
printf("ATR Function PASS!!\n");
} else {
printf("ATR Function FAIL!!\n");
}

scr.baud_div = (scr.scclk_div + 1) * (scatr.F) / (scatr.D) - 1;
scr_set_baud_divisor(&scr, pscr->baud_div);

scr_buffer_flush(&scr.rxbuf); // clean rxbuffer
stage = sts_send_cmd;
} else {
stage = sts_start_deact;
}
}
break;

case sts_send_cmd: //这里应该可以加入我们想要的沟通命令
{
uint8_t cmp_rlt = 0;
if (ic_card_send_cmd[card_name][0]) {
for (i = 0; i < ic_card_send_cmd[card_name][0]; i++) {
uint8_t send = ic_card_send_cmd[card_name][i + 1];
scr_write_fifo(&scr, send);
}
msleep(1000);
scr_rx_fifo_read(rsp_temp);

for (i = 0; i < ic_card_rev_data[card_name][0]; i++) {
if (rsp_temp[i] != ic_card_rev_data[card_name][i + 1]) {
cmp_rlt = 1;
}
}
if (cmp_rlt) {
printf("Communication Command Error: ");
for (i = 0; i < ic_card_rev_data[card_name][0]; i++)
printf("0x%02x ", rsp_temp[i]);
printf("\n");
scr_ret++;
} else {
printf("Communication Command Respone PASS!!\n");
}
} else {
printf("No communication command, No command test!!\n");
stage = sts_idle;
}
msleep(1000);
} break;
case sts_start_deact:
stage = sts_wait_deact;
scr_start_deactivation(&scr); /* Deactivation */
msleep(10);
break;
case sts_wait_deact:
if (!scr.activated) {
stage = sts_wait_disconnect;
scr_module_rst(SCR_NO);
scr_params_init();
smartcard_params_init(&scatr); /*set smart card protocol, v,i,frequency*/
scr_init(&scr);
}
break;
case sts_wait_disconnect:
if (!scr.detected)
stage = sts_wait_connect;

break;

case sts_idle:
msleep(50);
if (sts_idle == stage)
stage = sts_idle;
break;
default:
stage = sts_idle;
break;
}

return 0;
}

void scr_data_transfer_test(void)
{
scr_params_init();
scr_init(&scr);
reg_scr0_irq_handler();
scr_global_interrupt_enable(&scr);
while (1)
scr_test_process(&scr);
}

/* s32 scr_test(void) */
int scr_test1(int argc, char** argv)
{
scr_params_init();
/*register default check and read write check*/
scr_system_setup(SCR_NO);

if (scr_reg_test() != 1)
return -1;

/*SCR Control and smart card data transfer test*/
scr_system_setup(SCR_NO);

scr_data_transfer_test();

return 0;
}
FINSH_FUNCTION_EXPORT_CMD(scr_test1, hal_smartcard, smartcard);