SmartAudio/lichee/linux-4.9/drivers/char/sunxi-scr/smartcard.c

326 lines
6.2 KiB
C
Executable File

/*
* drivers/char/sunxi-scr/smartcard.c
*
* Copyright (C) 2016 Allwinner.
* fuzhaoke <fuzhaoke@allwinnertech.com>
*
* Decode for ISO7816 smart card
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include "smartcard.h"
void smartcard_ta1_decode(struct smc_atr_para *psmc_atr, uint8_t ta1)
{
pr_debug("%s: enter!!\n", __func__);
switch ((ta1>>4)&0xf) {
case 0x0:
psmc_atr->FMAX = 4;
psmc_atr->F = 372;
break;
case 0x1:
psmc_atr->FMAX = 5;
psmc_atr->F = 372;
break;
case 0x2:
psmc_atr->FMAX = 6;
psmc_atr->F = 558;
break;
case 0x3:
psmc_atr->FMAX = 8;
psmc_atr->F = 744;
break;
case 0x4:
psmc_atr->FMAX = 12;
psmc_atr->F = 1116;
break;
case 0x5:
psmc_atr->FMAX = 16;
psmc_atr->F = 1488;
break;
case 0x6:
psmc_atr->FMAX = 20;
psmc_atr->F = 1860;
break;
case 0x9:
psmc_atr->FMAX = 5;
psmc_atr->F = 512;
break;
case 0xA:
psmc_atr->FMAX = 7;
psmc_atr->F = 768;
break;
case 0xB:
psmc_atr->FMAX = 10;
psmc_atr->F = 1024;
break;
case 0xC:
psmc_atr->FMAX = 15;
psmc_atr->F = 1536;
break;
case 0xD:
psmc_atr->FMAX = 20;
psmc_atr->F = 2048;
break;
default: /* 0x7/0x8/0xE/0xF */
psmc_atr->FMAX = 4;
psmc_atr->F = 372;
pr_err("Unsupport ta1 = 0x%x\n", ta1);
break;
}
switch (ta1&0xf) {
case 0x1:
psmc_atr->D = 1;
break;
case 0x2:
psmc_atr->D = 2;
break;
case 0x3:
psmc_atr->D = 4;
break;
case 0x4:
psmc_atr->D = 8;
break;
case 0x5:
psmc_atr->D = 16;
break;
case 0x6:
psmc_atr->D = 32;
break;
case 0x8:
psmc_atr->D = 12;
break;
case 0x9:
psmc_atr->D = 20;
break;
default: /* 0x0/0x7/0xA/0xB/0xC/0xD/0xE/0xF */
psmc_atr->D = 1;
pr_err("Unsupport ta1 = 0x%x\n", ta1);
break;
}
}
void smartcard_tb1_decode(struct smc_atr_para *psmc_atr, uint8_t tb1)
{
pr_debug("%s: enter!!\n", __func__);
switch ((tb1>>5)&0x3) {
case 0:
psmc_atr->I = 25;
break;
case 1:
psmc_atr->I = 50;
break;
case 2:
psmc_atr->I = 100;
break;
default:
psmc_atr->I = 50;
}
if (((tb1&0x1f) > 4) && ((tb1&0x1f) < 26))
psmc_atr->P = (tb1&0x1f); /* 5~25 in Volts */
else if (0 == (tb1&0x1f))
psmc_atr->P = 0;
else
psmc_atr->P = 5;
}
/* ATR data format: max 33 byte(include TS)
* [TS|T0|TA1|TB1|TC1|TD1|TA2|TB2|TC2|TD2|...|T1|T2|........|TK|TCK]
* |-------- max 16 byte --------------|-- max 15 byte --|verify
* |--------------------- max 33 byte -------------------------|
* TS: Initial character
* 0x3b:direct convention, 0x3f:inverse convention
* T0: Format character
* [bit7|bit6|bit5|bit4|bit3|bit2|bit1|bit0]
* |------- Y1 --------|-------- K --------|
* Y1: indicator for the presence of the interface character
* TA1 is transmitted when bit[4] = 1
* TB1 is transmitted when bit[5] = 1
* TC1 is transmitted when bit[6] = 1
* TD1 is transmitted when bit[7] = 1
* K: history number
* TAi: Interface character
* code FI,DI
* TBi: Interface character
* code II,PI
* TCi: Interface character
* code N
* TDi: Interface character
* code Yi+1, T
* [bit7|bit6|bit5|bit4|bit3|bit2|bit1|bit0]
* |------ Yi + 1 -----|-------- T --------|
* Yi + 1: indicator for the presence of the interface character
* TAi+1 is transmitted when bit[4] = 1
* TBi+1 is transmitted when bit[5] = 1
* TCi+1 is transmitted when bit[6] = 1
* TDi+1 is transmitted when bit[7] = 1
* T: Protocol type for subsequent transmission
* T=0: character transmit
* T=1: block transmit
* T=other: reserved
* T1~TK: history byte, information of the card like manufacture name
* TCK: verify character, make sure the data is correctly
*/
void smartcard_atr_decode(struct smc_atr_para *psmc_atr, struct smc_pps_para *psmc_pps,
uint8_t *pdata, uint8_t with_ts)
{
uint8_t index = 0;
uint8_t temp;
uint8_t i;
pr_debug("%s: Enter...\n", __func__);
psmc_pps->ppss = 0xff;
psmc_pps->pps0 = 0;
if (with_ts) {
psmc_atr->TS = pdata[0]; /* TS */
index++;
}
temp = pdata[index]; /* T0 */
index++;
psmc_atr->TK_NUM = temp & 0xf;
/* TA1 */
if (temp & 0x10) {
smartcard_ta1_decode(psmc_atr, pdata[index]);
psmc_pps->pps0 |= 0x1<<4;
psmc_pps->pps1 = pdata[index];
index++;
}
/* TB1 */
if (temp & 0x20) {
smartcard_tb1_decode(psmc_atr, pdata[index]);
index++;
}
/* TC1 */
if (temp & 0x40) {
psmc_atr->N = pdata[index] & 0xff;
index++;
}
/* TD1 */
if (temp & 0x80) {
pr_debug("%s: TD1 parse 0x%x !!\n", __func__, pdata[index]);
temp = pdata[index];
psmc_atr->T = temp & 0xf;
psmc_pps->pps0 |= temp & 0xf;
/* Adjust Guard Time */
if (psmc_atr->N == 0xff) {
if (psmc_atr->T == 1)
psmc_atr->N = 1;
else
psmc_atr->N = 2;
}
index++;
} else {
if (psmc_atr->N == 0xff)
psmc_atr->N = 2;
goto rx_tk;
}
/* TA2 */
if (temp & 0x10) {
pr_debug("TA2 Exist!!\n");
index++;
}
/* TB2 */
if (temp & 0x20) {
pr_debug("TB2 Exist!!\n");
index++;
}
/* TC2 */
if (temp & 0x40) {
pr_debug("TC2 Exist!!\n");
index++;
}
/* TD2 */
if (temp & 0x80) {
pr_debug("TD2 Exist!!\n");
temp = pdata[index];
index++;
} else {
goto rx_tk;
}
/* TA3 */
if (temp & 0x10) {
pr_debug("TA3 Exist!!\n");
index++;
}
/* TB3 */
if (temp & 0x20) {
pr_debug("TB3 Exist!!\n");
index++;
}
/* TC3 */
if (temp & 0x40) {
pr_debug("TC3 Exist!!\n");
index++;
}
/* TD3 */
if (temp & 0x80) {
pr_debug("TD3 Exist!!\n");
temp = pdata[index];
index++;
} else {
goto rx_tk;
}
/* TA4 */
if (temp & 0x10) {
pr_debug("TA4 Exist!!\n");
index++;
}
/* TB4 */
if (temp & 0x20) {
pr_debug("TB4 Exist!!\n");
index++;
}
/* TC4 */
if (temp & 0x40) {
pr_debug("TC4 Exist!!\n");
index++;
}
/* TD4 */
if (temp & 0x80) {
pr_debug("TD4 Exist!!\n");
temp = pdata[index];
index++;
}
rx_tk:
for (i = 0; i < (psmc_atr->TK_NUM); i++)
psmc_atr->TK[i] = pdata[index++];
psmc_pps->pck = psmc_pps->ppss;
psmc_pps->pck ^= psmc_pps->pps0;
if (psmc_pps->pps0&(0x1<<4))
psmc_pps->pck ^= psmc_pps->pps1;
if (psmc_pps->pps0&(0x1<<5))
psmc_pps->pck ^= psmc_pps->pps2;
if (psmc_pps->pps0&(0x1<<6))
psmc_pps->pck ^= psmc_pps->pps3;
}