📄 iccard.c
字号:
/************************************************************************************************
*
* Copyright (C) EVOC Co., LTD. 2003
*
* File name: IcCard.c
* Description:
*
* Revision history
* 2006.05.17 Zou Hong Bo start.
*
************************************************************************************************/
/* Include files--------------------------------------------------------------*/
//#include "iccard_hw.h"
#include <linux/version.h>
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/interrupt.h> /* We want interrupts */
#include <linux/miscdevice.h> /* for misc_register() and misc_deregister() */
#include <linux/fs.h> /* for struct 'file_operations' */
#include <linux/timer.h> /* for timeout interrupts */
#include <linux/param.h> /* for HZ. HZ = 100 and the timer step is 1/100 */
#include <linux/sched.h> /* for jiffies definition. jiffies is incremented*/
/* once for each clock tick; thus it's incremented*/
/* HZ times per secondes.*/
#include <linux/mm.h> /* for verify_area */
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/iccard.h>
#include <asm/irq.h> /* For IRQ_MACHSPEC */
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/arch/irqs.h>
#include <asm/arch/hardware.h>
#include <asm/arch/44b.h>
#include <asm/arch/def.h>
#define DEBUG_ICCARD // for debug only
//#define NULL 0
#define CPU_CARD 0x01
#define SAM_CARD 0x02
#define CPU_CARD_POW (1<<3)
#define SAM_CARD_POW (1<<2)
#define CPU_CARD_RST (1<<6)
#define SAM_CARD_RST (1)
#define IC_LED_POW (1<<8)
//#define TIMEROUT_ERR 0xff
#define MAX_TIME_OUT 0XFFF0
#define CARD_OUT (1<<12)
#define CARD_IN (1<<13)
//#define CARD_RX (rPDATC&CARD_IN )? 1:0
//#define CARD_TX_SET rPDATC = rPDATC|CARD_OUT
//#define CARD_TX_CLR rPDATC = rPDATC&(~CARD_OUT)
#define CARD_RX (inl(S3C44B0X_PDATC) & CARD_IN )? 1:0
#define CARD_TX_SET outl(inl(S3C44B0X_PDATC) | CARD_OUT,S3C44B0X_PDATC)
#define CARD_TX_CLR outl(inl(S3C44B0X_PDATC) &(~CARD_OUT),S3C44B0X_PDATC)
#define RE_REVEIVE_TIMES 3 //重发重收的次数
#define RE_SEND_TIMES 3 //重发重收的次数
#define etu_time_all 0x2ac
#define etu_time_half 0x366
#define ATR_MAX_LEN 32 //max atr len
#define TS_BIT 1
#define NOT_TS_BIT 0
#define LAST_BYTE 1
#define NOT_LAST_BYTE 0
#define POSITIVE_LOGIC 0
#define NEGATIVE_LOGIC 1
#define EVOC_ICCARD_BUF_SIZE 1024
#define TIMEOUT_MAX_CYCLE 1200000
#define REV_TS_TIMEOUT_CYCLE 40040 //about 17.2ms. >= 40000/f =40000/3.579MHz = 11.18ms
static struct ICCARDFIFO {
unsigned char buffer[EVOC_ICCARD_BUF_SIZE];
int len;
}iccardfifo;
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_IC_dir,devfs_ICraw;
#endif
#define IC_MAJOR 115
#define IC_MINOR 0
#define DEVICE_NAME "s3c44b0ic"
static int TC2_WI = 10;
static int logic_mode_sam = POSITIVE_LOGIC;
static int logic_mode_usr = POSITIVE_LOGIC;
static unsigned char protect_time_sam = 0;
static unsigned char protect_time_usr = 0;
static int samcard_err = -1;
static int usrcard_err = -1;
static int card_selected=NONECARD;
unsigned char iccard_ctr=0;
static unsigned long usrcard_max_cycle = TIMEOUT_MAX_CYCLE;
static const char* __file__ = __FILE__;
static int iccard_device_open = 0; /* number of open device to prevent concurrent*/
/* access to the same device */
static char time_flag=0;
//*******************************************************
//*******************************************************
static unsigned char swapbits(unsigned char i)
{
return i >> 7
| (i & 0x40) >> 5
| (i & 0x20) >> 3
| (i & 0x10) >> 1
| (i & 0x08) << 1
| (i & 0x04) << 3
| (i & 0x02) << 5
| i << 7;
}
//*******************************************************
//*******************************************************
static void EVOC_LED_ON(void)
{
outl((inl(S3C44B0X_PDATC) & (~IC_LED_POW )),S3C44B0X_PDATC);
}
//*******************************************************
//*******************************************************
static void EVOC_LED_OFF(void)
{
outl((inl(S3C44B0X_PDATC) | (IC_LED_POW)),S3C44B0X_PDATC);
}
//*******************************************************
//*******************************************************
static void etu_time_handle(int irq,void *dev_id,struct pt_regs *regs)
{
time_flag = 1;
printk("input time interrupt\n");
//outl(0x777, S3C44B0X_TCNTB1);
s3c44b0x_clear_pb(S3C44B0X_INTERRUPT_TIMER1);
//outl(0x1000, S3C44B0X_F_ISPC);
}
//*******************************************************
//*******************************************************
/*static void delay_1200_cycle(void)
{
//500 cycles=148us
int i;
for(i=0;i<2000;i++);
}*/
//*******************************************************
//*******************************************************
static void delay_cycle(unsigned int count)
{
//500 cycles=148us
for(;count>0;count--);
}
//*******************************************************
//*******************************************************
static void EVOC_iccard_set_port(void)
{
u_int32_t tmod;
outl(0xf1555555,S3C44B0X_PCONC);
//rPCONC = 0xf1555555; // rxd1 as input; txd1 as output
// pc12 is txd1; pc13 is rxd1
outl(0xF9FF,S3C44B0X_PDATC);
//rPDATC = 0xF9FF;
tmod = inl(S3C44B0X_PCONE);
tmod &= ~(0x03<<6);
tmod |= 0x01<<6;
tmod &= ~(0x03<<16);
tmod |= 0x01<<16;
outl(tmod,S3C44B0X_PCONE);
outl((inl(S3C44B0X_PDATE) & 0x0f7),S3C44B0X_PDATE);
tmod = inl(S3C44B0X_PCONG);
tmod &= ~(0x03<<12);
tmod |= 0x01<<12;
outl(tmod,S3C44B0X_PCONG);
outl((inl(S3C44B0X_PDATG) | 0x40),S3C44B0X_PDATG);
// zhp add 20060608 for GPF6
outl(0X8040A,S3C44B0X_PCONF);
outl(0X14F,S3C44B0X_PDATF);
//rPCONF = 0X8040A;
//rPDATF = 0X14F;
}
//*******************************************************
//*******************************************************
static void EVOC_select_usr(void)
{
outl((inl(S3C44B0X_PDATE) | 0x08),S3C44B0X_PDATE);
}
//*******************************************************
//*******************************************************
static void EVOC_select_sam(void)
{
outl((inl(S3C44B0X_PDATE) & 0x0f7),S3C44B0X_PDATE);
}
//*******************************************************
//*******************************************************
static void EVOC_usr_set_card_rst(void)
{
//outl(inl(S3C44B0X_PDATE) | 0x08,S3C44B0X_PDATE);
outl((inl(S3C44B0X_PDATG) & (~CPU_CARD_RST)),S3C44B0X_PDATG);
}
//*******************************************************
//*******************************************************
static void EVOC_usr_clr_card_rst(void)
{
//outl(inl(S3C44B0X_PDATE) | 0x08,S3C44B0X_PDATE);
outl((inl(S3C44B0X_PDATG) | (CPU_CARD_RST)),S3C44B0X_PDATG);
}
//*******************************************************
//*******************************************************
static void EVOC_usr_card_pwr_off(void)
{
outl((inl(S3C44B0X_PDATC) | (CPU_CARD_POW)),S3C44B0X_PDATC);
EVOC_LED_OFF();
}
//*******************************************************
//*******************************************************
static void EVOC_usr_card_pwr_on(void)
{
outl((inl(S3C44B0X_PDATC) & (~CPU_CARD_POW)),S3C44B0X_PDATC);
EVOC_LED_ON();
}
//*******************************************************
//*******************************************************
static void EVOC_sam_set_card_rst(void)
{
//outl(inl(S3C44B0X_PDATE) & 0x77,S3C44B0X_PDATE);
outl((inl(S3C44B0X_PDATC) & (~SAM_CARD_RST)),S3C44B0X_PDATC);
}
//*******************************************************
//*******************************************************
static void EVOC_sam_clr_card_rst(void){
//outl(inl(S3C44B0X_PDATE) & 0x77,S3C44B0X_PDATE);
outl((inl(S3C44B0X_PDATC) | (SAM_CARD_RST)),S3C44B0X_PDATC);
}
//*******************************************************
//*******************************************************
static void EVOC_sam_card_pwr_off(void){
outl((inl(S3C44B0X_PDATC) | (SAM_CARD_POW)),S3C44B0X_PDATC);
EVOC_LED_OFF();
}
//*******************************************************
//*******************************************************
static void EVOC_sam_card_pwr_on(void){
outl((inl(S3C44B0X_PDATC) & (~SAM_CARD_POW)),S3C44B0X_PDATC);
EVOC_LED_ON();
}
//*******************************************************
//*******************************************************
static void EVOC_sam_card_release(void){
EVOC_sam_clr_card_rst();
EVOC_sam_card_pwr_off();
iccardfifo.len = 0;
}
//*******************************************************
//*******************************************************
static void EVOC_usr_card_release(void){
EVOC_usr_clr_card_rst();
EVOC_usr_card_pwr_off();
iccardfifo.len = 0;
}
//*******************************************************
//*******************************************************
int EVOC_show_card_err_msg(int errcode){
printk("\nerrcode = %d , ",errcode);
if (errcode>=0){
printk("OK!\n");
}
else if (errcode == TIMEROUT_ERR) {
printk("Time out err\n");
}
else if (errcode == PARITY1_ERR) {
printk("receive parity err\n");
}
else if (errcode == PARITY2_ERR) {
printk("send parity err\n");
}
else if (errcode == CARD_ERR) {
printk("card err, not cpu card\n");
}
else if (errcode == ATR_LEN_ERR) {
printk("card response len err\n");
}
else if (errcode == ATR_XOR_ERR) {
printk("card response parity err\n");
}
else if (errcode == NO_SELECTED_CARD_ERR) {
printk("No card be selected err\n");
}
else if (errcode == ADPU_ERR) {
printk("ADPU CMD format err\n");
}
else if (errcode == NO_CARD_ERR) {
printk("No card in card slot err\n");
}
else {
printk("other err\n");
}
return 0;
}
/*
static inline int ADD1(unsigned int a)
{
__asm__(
"mov r0, %0\n"
"1:\n"
"sub r0, r0, #1\n"
"cmp r0, #0\n"
"bne 1b"
: "=r"(a)
);
}
*/
//*******************************************************
//*******************************************************
void delay_half_etu_usr(void)
{ // about 52u //40MHz
int i;
for(i=0;i<760;i++);//760 101
//ADD1(700);
}
//*******************************************************
//*******************************************************
void delay_half_etu_sam(void)
{ // about 52u //40MHz
int i;
for(i=0;i<594;i++);//760 101
//ADD1(700);
}
//*******************************************************
//*******************************************************
void delay_one_etu(void)
{ // about 104u //40MHz
int i;
for(i=0;i<1515;i++);//1510 199us
//ADD1(1400);
}
//*******************************************************
//*******************************************************
static int EVOC_send_one_byte(unsigned char * send_data, int send_last_byte){
int i;
unsigned char senddata;
int re_send_times;
int send_parity_bit;
unsigned char protect_time=0;
re_send_times = 0;
if (card_selected==SAMCARD) {
protect_time = protect_time_sam;
if (logic_mode_sam == NEGATIVE_LOGIC) {
senddata = swapbits(*send_data);
}
else{
senddata = (*send_data);
}
}
else if(card_selected==USRCARD){
protect_time = protect_time_usr;
if (logic_mode_usr == NEGATIVE_LOGIC){
senddata = swapbits(*send_data);
}
else {
senddata = (*send_data);
}
}
else return NO_SELECTED_CARD_ERR;
send_parity_bit = ( ( senddata >> 7)
^( (senddata & 0x40) >> 6)
^( (senddata & 0x20) >> 5)
^( (senddata & 0x10) >> 4)
^( (senddata & 0x08) >> 3)
^( (senddata & 0x04) >> 2)
^( (senddata & 0x02) >> 1)
^( (senddata & 0x01) ) );
// if (senddata==0x84) send_parity_bit=1;
CARD_TX_SET;
delay_cycle(100);
while ( re_send_times < RE_SEND_TIMES )
{
CARD_TX_CLR; //start bit
delay_one_etu(); // 1 etu
for(i=0;i<8;i++)
{ //8 bit data
if ( (senddata>>i)&0x01 )
CARD_TX_SET;
else
CARD_TX_CLR;
delay_one_etu(); //2 - 9 etu
}
if ( send_parity_bit ) //parity bit
CARD_TX_SET;
else
CARD_TX_CLR;
delay_one_etu(); //10 etu
CARD_TX_SET;
delay_half_etu_usr();
if (card_selected==SAMCARD) delay_one_etu(); //0.5etu
if ( CARD_RX )
{ // send protect bit
delay_one_etu(); //12 etu
CARD_TX_SET;
if (send_last_byte==LAST_BYTE)
return 0;
if ( (protect_time==0)||(protect_time==0xff) )
return 0;
else
{
for(i=0;i<protect_time;i++)
{
delay_one_etu(); // 13 ~ (12+N) etu
}
return 0;
}
}
delay_one_etu(); //12 etu, send err
delay_one_etu(); //13 etu
CARD_TX_SET;
re_send_times++;
}
return PARITY2_ERR;
}
//*******************************************************
//*******************************************************
static int EVOC_rev_one_byte(unsigned char * rev_data, unsigned int timeout, int rev_TS){
unsigned char * revdata;
//unsigned char temp;
unsigned int i,count;
int re_rev_times;
unsigned char parity_bit;
int card_logic_mode;
if (card_selected==SAMCARD)
{
card_logic_mode = logic_mode_sam;
}
else if(card_selected==USRCARD)
{
card_logic_mode = logic_mode_usr;
}
else return NO_SELECTED_CARD_ERR;
re_rev_times = 0;
revdata = rev_data;
while ( re_rev_times < RE_REVEIVE_TIMES )
{
count = 0;
CARD_TX_SET;
while ( CARD_RX )
{
count++;
if (count>=timeout)
{
return TIMEROUT_ERR;
}
}
if (card_selected==SAMCARD) delay_half_etu_sam(); //0.5etu
else delay_half_etu_usr();
for( i=0;i<8;i++)
{ // receive 8 bits data
delay_one_etu(); //1.5etu - 8.5etu
if ( card_logic_mode == POSITIVE_LOGIC )
{
if ( CARD_RX )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -