diff -drupN a/drivers/char/sunxi-scr/smartcard.c b/drivers/char/sunxi-scr/smartcard.c --- a/drivers/char/sunxi-scr/smartcard.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/char/sunxi-scr/smartcard.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,325 @@ +/* + * drivers/char/sunxi-scr/smartcard.c + * + * Copyright (C) 2016 Allwinner. + * fuzhaoke + * + * 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 +#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; +}