18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NFC Digital Protocol stack 48c2ecf20Sopenharmony_ci * Copyright (c) 2013, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "digital: %s: " fmt, __func__ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "digital.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SENS_REQ 0x26 128c2ecf20Sopenharmony_ci#define DIGITAL_CMD_ALL_REQ 0x52 138c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SEL_REQ_CL1 0x93 148c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SEL_REQ_CL2 0x95 158c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SEL_REQ_CL3 0x97 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DIGITAL_SDD_REQ_SEL_PAR 0x20 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define DIGITAL_SDD_RES_CT 0x88 208c2ecf20Sopenharmony_ci#define DIGITAL_SDD_RES_LEN 5 218c2ecf20Sopenharmony_ci#define DIGITAL_SEL_RES_LEN 1 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04)) 248c2ecf20Sopenharmony_ci#define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60)) 258c2ecf20Sopenharmony_ci#define DIGITAL_SEL_RES_IS_T4T(sel_res) ((sel_res) & 0x20) 268c2ecf20Sopenharmony_ci#define DIGITAL_SEL_RES_IS_NFC_DEP(sel_res) ((sel_res) & 0x40) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x0C00) == 0x0C00) 298c2ecf20Sopenharmony_ci#define DIGITAL_SENS_RES_IS_VALID(sens_res) \ 308c2ecf20Sopenharmony_ci ((!((sens_res) & 0x001F) && (((sens_res) & 0x0C00) == 0x0C00)) || \ 318c2ecf20Sopenharmony_ci (((sens_res) & 0x001F) && ((sens_res) & 0x0C00) != 0x0C00)) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define DIGITAL_MIFARE_READ_RES_LEN 16 348c2ecf20Sopenharmony_ci#define DIGITAL_MIFARE_ACK_RES 0x0A 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SENSB_REQ 0x05 378c2ecf20Sopenharmony_ci#define DIGITAL_SENSB_ADVANCED BIT(5) 388c2ecf20Sopenharmony_ci#define DIGITAL_SENSB_EXTENDED BIT(4) 398c2ecf20Sopenharmony_ci#define DIGITAL_SENSB_ALLB_REQ BIT(3) 408c2ecf20Sopenharmony_ci#define DIGITAL_SENSB_N(n) ((n) & 0x7) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SENSB_RES 0x50 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define DIGITAL_CMD_ATTRIB_REQ 0x1D 458c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P1_TR0_DEFAULT (0x0 << 6) 468c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P1_TR1_DEFAULT (0x0 << 4) 478c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P1_SUPRESS_EOS BIT(3) 488c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P1_SUPRESS_SOS BIT(2) 498c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P2_LISTEN_POLL_1 (0x0 << 6) 508c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P2_POLL_LISTEN_1 (0x0 << 4) 518c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P2_MAX_FRAME_256 0x8 528c2ecf20Sopenharmony_ci#define DIGITAL_ATTRIB_P4_DID(n) ((n) & 0xf) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SENSF_REQ 0x00 558c2ecf20Sopenharmony_ci#define DIGITAL_CMD_SENSF_RES 0x01 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define DIGITAL_SENSF_RES_MIN_LENGTH 17 588c2ecf20Sopenharmony_ci#define DIGITAL_SENSF_RES_RD_AP_B1 0x00 598c2ecf20Sopenharmony_ci#define DIGITAL_SENSF_RES_RD_AP_B2 0x8F 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define DIGITAL_SENSF_REQ_RC_NONE 0 628c2ecf20Sopenharmony_ci#define DIGITAL_SENSF_REQ_RC_SC 1 638c2ecf20Sopenharmony_ci#define DIGITAL_SENSF_REQ_RC_AP 2 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define DIGITAL_CMD_ISO15693_INVENTORY_REQ 0x01 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define DIGITAL_ISO15693_REQ_FLAG_DATA_RATE BIT(1) 688c2ecf20Sopenharmony_ci#define DIGITAL_ISO15693_REQ_FLAG_INVENTORY BIT(2) 698c2ecf20Sopenharmony_ci#define DIGITAL_ISO15693_REQ_FLAG_NB_SLOTS BIT(5) 708c2ecf20Sopenharmony_ci#define DIGITAL_ISO15693_RES_FLAG_ERROR BIT(0) 718c2ecf20Sopenharmony_ci#define DIGITAL_ISO15693_RES_IS_VALID(flags) \ 728c2ecf20Sopenharmony_ci (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define DIGITAL_ISO_DEP_I_PCB 0x02 758c2ecf20Sopenharmony_ci#define DIGITAL_ISO_DEP_PNI(pni) ((pni) & 0x01) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define DIGITAL_ISO_DEP_PCB_TYPE(pcb) ((pcb) & 0xC0) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define DIGITAL_ISO_DEP_I_BLOCK 0x00 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb) ((pcb) & 0x08) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic const u8 digital_ats_fsc[] = { 848c2ecf20Sopenharmony_ci 16, 24, 32, 40, 48, 64, 96, 128, 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define DIGITAL_ATS_FSCI(t0) ((t0) & 0x0F) 888c2ecf20Sopenharmony_ci#define DIGITAL_SENSB_FSCI(pi2) (((pi2) & 0xF0) >> 4) 898c2ecf20Sopenharmony_ci#define DIGITAL_ATS_MAX_FSC 256 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define DIGITAL_RATS_BYTE1 0xE0 928c2ecf20Sopenharmony_ci#define DIGITAL_RATS_PARAM 0x80 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct digital_sdd_res { 958c2ecf20Sopenharmony_ci u8 nfcid1[4]; 968c2ecf20Sopenharmony_ci u8 bcc; 978c2ecf20Sopenharmony_ci} __packed; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistruct digital_sel_req { 1008c2ecf20Sopenharmony_ci u8 sel_cmd; 1018c2ecf20Sopenharmony_ci u8 b2; 1028c2ecf20Sopenharmony_ci u8 nfcid1[4]; 1038c2ecf20Sopenharmony_ci u8 bcc; 1048c2ecf20Sopenharmony_ci} __packed; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct digital_sensb_req { 1078c2ecf20Sopenharmony_ci u8 cmd; 1088c2ecf20Sopenharmony_ci u8 afi; 1098c2ecf20Sopenharmony_ci u8 param; 1108c2ecf20Sopenharmony_ci} __packed; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistruct digital_sensb_res { 1138c2ecf20Sopenharmony_ci u8 cmd; 1148c2ecf20Sopenharmony_ci u8 nfcid0[4]; 1158c2ecf20Sopenharmony_ci u8 app_data[4]; 1168c2ecf20Sopenharmony_ci u8 proto_info[3]; 1178c2ecf20Sopenharmony_ci} __packed; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistruct digital_attrib_req { 1208c2ecf20Sopenharmony_ci u8 cmd; 1218c2ecf20Sopenharmony_ci u8 nfcid0[4]; 1228c2ecf20Sopenharmony_ci u8 param1; 1238c2ecf20Sopenharmony_ci u8 param2; 1248c2ecf20Sopenharmony_ci u8 param3; 1258c2ecf20Sopenharmony_ci u8 param4; 1268c2ecf20Sopenharmony_ci} __packed; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistruct digital_attrib_res { 1298c2ecf20Sopenharmony_ci u8 mbli_did; 1308c2ecf20Sopenharmony_ci} __packed; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistruct digital_sensf_req { 1338c2ecf20Sopenharmony_ci u8 cmd; 1348c2ecf20Sopenharmony_ci u8 sc1; 1358c2ecf20Sopenharmony_ci u8 sc2; 1368c2ecf20Sopenharmony_ci u8 rc; 1378c2ecf20Sopenharmony_ci u8 tsn; 1388c2ecf20Sopenharmony_ci} __packed; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistruct digital_sensf_res { 1418c2ecf20Sopenharmony_ci u8 cmd; 1428c2ecf20Sopenharmony_ci u8 nfcid2[8]; 1438c2ecf20Sopenharmony_ci u8 pad0[2]; 1448c2ecf20Sopenharmony_ci u8 pad1[3]; 1458c2ecf20Sopenharmony_ci u8 mrti_check; 1468c2ecf20Sopenharmony_ci u8 mrti_update; 1478c2ecf20Sopenharmony_ci u8 pad2; 1488c2ecf20Sopenharmony_ci u8 rd[2]; 1498c2ecf20Sopenharmony_ci} __packed; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistruct digital_iso15693_inv_req { 1528c2ecf20Sopenharmony_ci u8 flags; 1538c2ecf20Sopenharmony_ci u8 cmd; 1548c2ecf20Sopenharmony_ci u8 mask_len; 1558c2ecf20Sopenharmony_ci u64 mask; 1568c2ecf20Sopenharmony_ci} __packed; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistruct digital_iso15693_inv_res { 1598c2ecf20Sopenharmony_ci u8 flags; 1608c2ecf20Sopenharmony_ci u8 dsfid; 1618c2ecf20Sopenharmony_ci u64 uid; 1628c2ecf20Sopenharmony_ci} __packed; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, 1658c2ecf20Sopenharmony_ci struct nfc_target *target); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, 1688c2ecf20Sopenharmony_ci struct sk_buff *skb) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci u8 pcb; 1718c2ecf20Sopenharmony_ci u8 block_type; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (skb->len < 1) 1748c2ecf20Sopenharmony_ci return -EIO; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci pcb = *skb->data; 1778c2ecf20Sopenharmony_ci block_type = DIGITAL_ISO_DEP_PCB_TYPE(pcb); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* No support fo R-block nor S-block */ 1808c2ecf20Sopenharmony_ci if (block_type != DIGITAL_ISO_DEP_I_BLOCK) { 1818c2ecf20Sopenharmony_ci pr_err("ISO_DEP R-block and S-block not supported\n"); 1828c2ecf20Sopenharmony_ci return -EIO; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb)) { 1868c2ecf20Sopenharmony_ci pr_err("DID field in ISO_DEP PCB not supported\n"); 1878c2ecf20Sopenharmony_ci return -EIO; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci skb_pull(skb, 1); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciint digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, 1968c2ecf20Sopenharmony_ci struct sk_buff *skb) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * Chaining not supported so skb->len + 1 PCB byte + 2 CRC bytes must 2008c2ecf20Sopenharmony_ci * not be greater than remote FSC 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci if (skb->len + 3 > ddev->target_fsc) 2038c2ecf20Sopenharmony_ci return -EIO; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci skb_push(skb, 1); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci *skb->data = DIGITAL_ISO_DEP_I_PCB | ddev->curr_nfc_dep_pni; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 2108c2ecf20Sopenharmony_ci DIGITAL_ISO_DEP_PNI(ddev->curr_nfc_dep_pni + 1); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, 2168c2ecf20Sopenharmony_ci struct sk_buff *resp) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct nfc_target *target = arg; 2198c2ecf20Sopenharmony_ci u8 fsdi; 2208c2ecf20Sopenharmony_ci int rc; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 2238c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 2248c2ecf20Sopenharmony_ci resp = NULL; 2258c2ecf20Sopenharmony_ci goto exit; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (resp->len < 2) { 2298c2ecf20Sopenharmony_ci rc = -EIO; 2308c2ecf20Sopenharmony_ci goto exit; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci fsdi = DIGITAL_ATS_FSCI(resp->data[1]); 2348c2ecf20Sopenharmony_ci if (fsdi >= 8) 2358c2ecf20Sopenharmony_ci ddev->target_fsc = DIGITAL_ATS_MAX_FSC; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci ddev->target_fsc = digital_ats_fsc[fsdi]; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciexit: 2448c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 2458c2ecf20Sopenharmony_ci kfree(target); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (rc) 2488c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int digital_in_send_rats(struct nfc_digital_dev *ddev, 2528c2ecf20Sopenharmony_ci struct nfc_target *target) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci int rc; 2558c2ecf20Sopenharmony_ci struct sk_buff *skb; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 2); 2588c2ecf20Sopenharmony_ci if (!skb) 2598c2ecf20Sopenharmony_ci return -ENOMEM; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci skb_put_u8(skb, DIGITAL_RATS_BYTE1); 2628c2ecf20Sopenharmony_ci skb_put_u8(skb, DIGITAL_RATS_PARAM); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_ats, 2658c2ecf20Sopenharmony_ci target); 2668c2ecf20Sopenharmony_ci if (rc) 2678c2ecf20Sopenharmony_ci kfree_skb(skb); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return rc; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, 2738c2ecf20Sopenharmony_ci struct sk_buff *resp) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct nfc_target *target = arg; 2768c2ecf20Sopenharmony_ci int rc; 2778c2ecf20Sopenharmony_ci u8 sel_res; 2788c2ecf20Sopenharmony_ci u8 nfc_proto; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 2818c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 2828c2ecf20Sopenharmony_ci resp = NULL; 2838c2ecf20Sopenharmony_ci goto exit; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) { 2878c2ecf20Sopenharmony_ci rc = digital_skb_check_crc_a(resp); 2888c2ecf20Sopenharmony_ci if (rc) { 2898c2ecf20Sopenharmony_ci PROTOCOL_ERR("4.4.1.3"); 2908c2ecf20Sopenharmony_ci goto exit; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (resp->len != DIGITAL_SEL_RES_LEN) { 2958c2ecf20Sopenharmony_ci rc = -EIO; 2968c2ecf20Sopenharmony_ci goto exit; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci sel_res = resp->data[0]; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res)) { 3028c2ecf20Sopenharmony_ci rc = digital_in_send_sdd_req(ddev, target); 3038c2ecf20Sopenharmony_ci if (rc) 3048c2ecf20Sopenharmony_ci goto exit; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci goto exit_free_skb; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci target->sel_res = sel_res; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { 3128c2ecf20Sopenharmony_ci nfc_proto = NFC_PROTO_MIFARE; 3138c2ecf20Sopenharmony_ci } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { 3148c2ecf20Sopenharmony_ci nfc_proto = NFC_PROTO_NFC_DEP; 3158c2ecf20Sopenharmony_ci } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { 3168c2ecf20Sopenharmony_ci rc = digital_in_send_rats(ddev, target); 3178c2ecf20Sopenharmony_ci if (rc) 3188c2ecf20Sopenharmony_ci goto exit; 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * Skip target_found and don't free it for now. This will be 3218c2ecf20Sopenharmony_ci * done when receiving the ATS 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci goto exit_free_skb; 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 3268c2ecf20Sopenharmony_ci goto exit; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci rc = digital_target_found(ddev, target, nfc_proto); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciexit: 3328c2ecf20Sopenharmony_ci kfree(target); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciexit_free_skb: 3358c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (rc) 3388c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int digital_in_send_sel_req(struct nfc_digital_dev *ddev, 3428c2ecf20Sopenharmony_ci struct nfc_target *target, 3438c2ecf20Sopenharmony_ci struct digital_sdd_res *sdd_res) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct sk_buff *skb; 3468c2ecf20Sopenharmony_ci struct digital_sel_req *sel_req; 3478c2ecf20Sopenharmony_ci u8 sel_cmd; 3488c2ecf20Sopenharmony_ci int rc; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(struct digital_sel_req)); 3518c2ecf20Sopenharmony_ci if (!skb) 3528c2ecf20Sopenharmony_ci return -ENOMEM; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci skb_put(skb, sizeof(struct digital_sel_req)); 3558c2ecf20Sopenharmony_ci sel_req = (struct digital_sel_req *)skb->data; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (target->nfcid1_len <= 4) 3588c2ecf20Sopenharmony_ci sel_cmd = DIGITAL_CMD_SEL_REQ_CL1; 3598c2ecf20Sopenharmony_ci else if (target->nfcid1_len < 10) 3608c2ecf20Sopenharmony_ci sel_cmd = DIGITAL_CMD_SEL_REQ_CL2; 3618c2ecf20Sopenharmony_ci else 3628c2ecf20Sopenharmony_ci sel_cmd = DIGITAL_CMD_SEL_REQ_CL3; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci sel_req->sel_cmd = sel_cmd; 3658c2ecf20Sopenharmony_ci sel_req->b2 = 0x70; 3668c2ecf20Sopenharmony_ci memcpy(sel_req->nfcid1, sdd_res->nfcid1, 4); 3678c2ecf20Sopenharmony_ci sel_req->bcc = sdd_res->bcc; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) { 3708c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 3718c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A); 3728c2ecf20Sopenharmony_ci if (rc) 3738c2ecf20Sopenharmony_ci goto exit; 3748c2ecf20Sopenharmony_ci } else { 3758c2ecf20Sopenharmony_ci digital_skb_add_crc_a(skb); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sel_res, 3798c2ecf20Sopenharmony_ci target); 3808c2ecf20Sopenharmony_ciexit: 3818c2ecf20Sopenharmony_ci if (rc) 3828c2ecf20Sopenharmony_ci kfree_skb(skb); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return rc; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void digital_in_recv_sdd_res(struct nfc_digital_dev *ddev, void *arg, 3888c2ecf20Sopenharmony_ci struct sk_buff *resp) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct nfc_target *target = arg; 3918c2ecf20Sopenharmony_ci struct digital_sdd_res *sdd_res; 3928c2ecf20Sopenharmony_ci int rc; 3938c2ecf20Sopenharmony_ci u8 offset, size; 3948c2ecf20Sopenharmony_ci u8 i, bcc; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 3978c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 3988c2ecf20Sopenharmony_ci resp = NULL; 3998c2ecf20Sopenharmony_ci goto exit; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (resp->len < DIGITAL_SDD_RES_LEN) { 4038c2ecf20Sopenharmony_ci PROTOCOL_ERR("4.7.2.8"); 4048c2ecf20Sopenharmony_ci rc = -EINVAL; 4058c2ecf20Sopenharmony_ci goto exit; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci sdd_res = (struct digital_sdd_res *)resp->data; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci for (i = 0, bcc = 0; i < 4; i++) 4118c2ecf20Sopenharmony_ci bcc ^= sdd_res->nfcid1[i]; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (bcc != sdd_res->bcc) { 4148c2ecf20Sopenharmony_ci PROTOCOL_ERR("4.7.2.6"); 4158c2ecf20Sopenharmony_ci rc = -EINVAL; 4168c2ecf20Sopenharmony_ci goto exit; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (sdd_res->nfcid1[0] == DIGITAL_SDD_RES_CT) { 4208c2ecf20Sopenharmony_ci offset = 1; 4218c2ecf20Sopenharmony_ci size = 3; 4228c2ecf20Sopenharmony_ci } else { 4238c2ecf20Sopenharmony_ci offset = 0; 4248c2ecf20Sopenharmony_ci size = 4; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci memcpy(target->nfcid1 + target->nfcid1_len, sdd_res->nfcid1 + offset, 4288c2ecf20Sopenharmony_ci size); 4298c2ecf20Sopenharmony_ci target->nfcid1_len += size; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci rc = digital_in_send_sel_req(ddev, target, sdd_res); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ciexit: 4348c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (rc) { 4378c2ecf20Sopenharmony_ci kfree(target); 4388c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, 4438c2ecf20Sopenharmony_ci struct nfc_target *target) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci int rc; 4468c2ecf20Sopenharmony_ci struct sk_buff *skb; 4478c2ecf20Sopenharmony_ci u8 sel_cmd; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 4508c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_STANDARD); 4518c2ecf20Sopenharmony_ci if (rc) 4528c2ecf20Sopenharmony_ci return rc; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 2); 4558c2ecf20Sopenharmony_ci if (!skb) 4568c2ecf20Sopenharmony_ci return -ENOMEM; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (target->nfcid1_len == 0) 4598c2ecf20Sopenharmony_ci sel_cmd = DIGITAL_CMD_SEL_REQ_CL1; 4608c2ecf20Sopenharmony_ci else if (target->nfcid1_len == 3) 4618c2ecf20Sopenharmony_ci sel_cmd = DIGITAL_CMD_SEL_REQ_CL2; 4628c2ecf20Sopenharmony_ci else 4638c2ecf20Sopenharmony_ci sel_cmd = DIGITAL_CMD_SEL_REQ_CL3; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci skb_put_u8(skb, sel_cmd); 4668c2ecf20Sopenharmony_ci skb_put_u8(skb, DIGITAL_SDD_REQ_SEL_PAR); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sdd_res, 4698c2ecf20Sopenharmony_ci target); 4708c2ecf20Sopenharmony_ci if (rc) 4718c2ecf20Sopenharmony_ci kfree_skb(skb); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return rc; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void digital_in_recv_sens_res(struct nfc_digital_dev *ddev, void *arg, 4778c2ecf20Sopenharmony_ci struct sk_buff *resp) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct nfc_target *target = NULL; 4808c2ecf20Sopenharmony_ci int rc; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 4838c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 4848c2ecf20Sopenharmony_ci resp = NULL; 4858c2ecf20Sopenharmony_ci goto exit; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (resp->len < sizeof(u16)) { 4898c2ecf20Sopenharmony_ci rc = -EIO; 4908c2ecf20Sopenharmony_ci goto exit; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci target = kzalloc(sizeof(struct nfc_target), GFP_KERNEL); 4948c2ecf20Sopenharmony_ci if (!target) { 4958c2ecf20Sopenharmony_ci rc = -ENOMEM; 4968c2ecf20Sopenharmony_ci goto exit; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci target->sens_res = __le16_to_cpu(*(__le16 *)resp->data); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (!DIGITAL_SENS_RES_IS_VALID(target->sens_res)) { 5028c2ecf20Sopenharmony_ci PROTOCOL_ERR("4.6.3.3"); 5038c2ecf20Sopenharmony_ci rc = -EINVAL; 5048c2ecf20Sopenharmony_ci goto exit; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (DIGITAL_SENS_RES_IS_T1T(target->sens_res)) 5088c2ecf20Sopenharmony_ci rc = digital_target_found(ddev, target, NFC_PROTO_JEWEL); 5098c2ecf20Sopenharmony_ci else 5108c2ecf20Sopenharmony_ci rc = digital_in_send_sdd_req(ddev, target); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ciexit: 5138c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (rc) { 5168c2ecf20Sopenharmony_ci kfree(target); 5178c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciint digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct sk_buff *skb; 5248c2ecf20Sopenharmony_ci int rc; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, 5278c2ecf20Sopenharmony_ci NFC_DIGITAL_RF_TECH_106A); 5288c2ecf20Sopenharmony_ci if (rc) 5298c2ecf20Sopenharmony_ci return rc; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 5328c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_SHORT); 5338c2ecf20Sopenharmony_ci if (rc) 5348c2ecf20Sopenharmony_ci return rc; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 5378c2ecf20Sopenharmony_ci if (!skb) 5388c2ecf20Sopenharmony_ci return -ENOMEM; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci skb_put_u8(skb, DIGITAL_CMD_SENS_REQ); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sens_res, NULL); 5438c2ecf20Sopenharmony_ci if (rc) 5448c2ecf20Sopenharmony_ci kfree_skb(skb); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return rc; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciint digital_in_recv_mifare_res(struct sk_buff *resp) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci /* Successful READ command response is 16 data bytes + 2 CRC bytes long. 5528c2ecf20Sopenharmony_ci * Since the driver can't differentiate a ACK/NACK response from a valid 5538c2ecf20Sopenharmony_ci * READ response, the CRC calculation must be handled at digital level 5548c2ecf20Sopenharmony_ci * even if the driver supports it for this technology. 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_ci if (resp->len == DIGITAL_MIFARE_READ_RES_LEN + DIGITAL_CRC_LEN) { 5578c2ecf20Sopenharmony_ci if (digital_skb_check_crc_a(resp)) { 5588c2ecf20Sopenharmony_ci PROTOCOL_ERR("9.4.1.2"); 5598c2ecf20Sopenharmony_ci return -EIO; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* ACK response (i.e. successful WRITE). */ 5668c2ecf20Sopenharmony_ci if (resp->len == 1 && resp->data[0] == DIGITAL_MIFARE_ACK_RES) { 5678c2ecf20Sopenharmony_ci resp->data[0] = 0; 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* NACK and any other responses are treated as error. */ 5728c2ecf20Sopenharmony_ci return -EIO; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic void digital_in_recv_attrib_res(struct nfc_digital_dev *ddev, void *arg, 5768c2ecf20Sopenharmony_ci struct sk_buff *resp) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct nfc_target *target = arg; 5798c2ecf20Sopenharmony_ci struct digital_attrib_res *attrib_res; 5808c2ecf20Sopenharmony_ci int rc; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 5838c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 5848c2ecf20Sopenharmony_ci resp = NULL; 5858c2ecf20Sopenharmony_ci goto exit; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (resp->len < sizeof(*attrib_res)) { 5898c2ecf20Sopenharmony_ci PROTOCOL_ERR("12.6.2"); 5908c2ecf20Sopenharmony_ci rc = -EIO; 5918c2ecf20Sopenharmony_ci goto exit; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci attrib_res = (struct digital_attrib_res *)resp->data; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (attrib_res->mbli_did & 0x0f) { 5978c2ecf20Sopenharmony_ci PROTOCOL_ERR("12.6.2.1"); 5988c2ecf20Sopenharmony_ci rc = -EIO; 5998c2ecf20Sopenharmony_ci goto exit; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443_B); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciexit: 6058c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 6068c2ecf20Sopenharmony_ci kfree(target); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (rc) 6098c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int digital_in_send_attrib_req(struct nfc_digital_dev *ddev, 6138c2ecf20Sopenharmony_ci struct nfc_target *target, 6148c2ecf20Sopenharmony_ci struct digital_sensb_res *sensb_res) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct digital_attrib_req *attrib_req; 6178c2ecf20Sopenharmony_ci struct sk_buff *skb; 6188c2ecf20Sopenharmony_ci int rc; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(*attrib_req)); 6218c2ecf20Sopenharmony_ci if (!skb) 6228c2ecf20Sopenharmony_ci return -ENOMEM; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci attrib_req = skb_put(skb, sizeof(*attrib_req)); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci attrib_req->cmd = DIGITAL_CMD_ATTRIB_REQ; 6278c2ecf20Sopenharmony_ci memcpy(attrib_req->nfcid0, sensb_res->nfcid0, 6288c2ecf20Sopenharmony_ci sizeof(attrib_req->nfcid0)); 6298c2ecf20Sopenharmony_ci attrib_req->param1 = DIGITAL_ATTRIB_P1_TR0_DEFAULT | 6308c2ecf20Sopenharmony_ci DIGITAL_ATTRIB_P1_TR1_DEFAULT; 6318c2ecf20Sopenharmony_ci attrib_req->param2 = DIGITAL_ATTRIB_P2_LISTEN_POLL_1 | 6328c2ecf20Sopenharmony_ci DIGITAL_ATTRIB_P2_POLL_LISTEN_1 | 6338c2ecf20Sopenharmony_ci DIGITAL_ATTRIB_P2_MAX_FRAME_256; 6348c2ecf20Sopenharmony_ci attrib_req->param3 = sensb_res->proto_info[1] & 0x07; 6358c2ecf20Sopenharmony_ci attrib_req->param4 = DIGITAL_ATTRIB_P4_DID(0); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_attrib_res, 6388c2ecf20Sopenharmony_ci target); 6398c2ecf20Sopenharmony_ci if (rc) 6408c2ecf20Sopenharmony_ci kfree_skb(skb); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci return rc; 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic void digital_in_recv_sensb_res(struct nfc_digital_dev *ddev, void *arg, 6468c2ecf20Sopenharmony_ci struct sk_buff *resp) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct nfc_target *target = NULL; 6498c2ecf20Sopenharmony_ci struct digital_sensb_res *sensb_res; 6508c2ecf20Sopenharmony_ci u8 fsci; 6518c2ecf20Sopenharmony_ci int rc; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 6548c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 6558c2ecf20Sopenharmony_ci resp = NULL; 6568c2ecf20Sopenharmony_ci goto exit; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (resp->len != sizeof(*sensb_res)) { 6608c2ecf20Sopenharmony_ci PROTOCOL_ERR("5.6.2.1"); 6618c2ecf20Sopenharmony_ci rc = -EIO; 6628c2ecf20Sopenharmony_ci goto exit; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci sensb_res = (struct digital_sensb_res *)resp->data; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (sensb_res->cmd != DIGITAL_CMD_SENSB_RES) { 6688c2ecf20Sopenharmony_ci PROTOCOL_ERR("5.6.2"); 6698c2ecf20Sopenharmony_ci rc = -EIO; 6708c2ecf20Sopenharmony_ci goto exit; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (!(sensb_res->proto_info[1] & BIT(0))) { 6748c2ecf20Sopenharmony_ci PROTOCOL_ERR("5.6.2.12"); 6758c2ecf20Sopenharmony_ci rc = -EIO; 6768c2ecf20Sopenharmony_ci goto exit; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (sensb_res->proto_info[1] & BIT(3)) { 6808c2ecf20Sopenharmony_ci PROTOCOL_ERR("5.6.2.16"); 6818c2ecf20Sopenharmony_ci rc = -EIO; 6828c2ecf20Sopenharmony_ci goto exit; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci fsci = DIGITAL_SENSB_FSCI(sensb_res->proto_info[1]); 6868c2ecf20Sopenharmony_ci if (fsci >= 8) 6878c2ecf20Sopenharmony_ci ddev->target_fsc = DIGITAL_ATS_MAX_FSC; 6888c2ecf20Sopenharmony_ci else 6898c2ecf20Sopenharmony_ci ddev->target_fsc = digital_ats_fsc[fsci]; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci target = kzalloc(sizeof(struct nfc_target), GFP_KERNEL); 6928c2ecf20Sopenharmony_ci if (!target) { 6938c2ecf20Sopenharmony_ci rc = -ENOMEM; 6948c2ecf20Sopenharmony_ci goto exit; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci rc = digital_in_send_attrib_req(ddev, target, sensb_res); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ciexit: 7008c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (rc) { 7038c2ecf20Sopenharmony_ci kfree(target); 7048c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ciint digital_in_send_sensb_req(struct nfc_digital_dev *ddev, u8 rf_tech) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct digital_sensb_req *sensb_req; 7118c2ecf20Sopenharmony_ci struct sk_buff *skb; 7128c2ecf20Sopenharmony_ci int rc; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, 7158c2ecf20Sopenharmony_ci NFC_DIGITAL_RF_TECH_106B); 7168c2ecf20Sopenharmony_ci if (rc) 7178c2ecf20Sopenharmony_ci return rc; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 7208c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCB); 7218c2ecf20Sopenharmony_ci if (rc) 7228c2ecf20Sopenharmony_ci return rc; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(*sensb_req)); 7258c2ecf20Sopenharmony_ci if (!skb) 7268c2ecf20Sopenharmony_ci return -ENOMEM; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci sensb_req = skb_put(skb, sizeof(*sensb_req)); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci sensb_req->cmd = DIGITAL_CMD_SENSB_REQ; 7318c2ecf20Sopenharmony_ci sensb_req->afi = 0x00; /* All families and sub-families */ 7328c2ecf20Sopenharmony_ci sensb_req->param = DIGITAL_SENSB_N(0); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sensb_res, 7358c2ecf20Sopenharmony_ci NULL); 7368c2ecf20Sopenharmony_ci if (rc) 7378c2ecf20Sopenharmony_ci kfree_skb(skb); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return rc; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg, 7438c2ecf20Sopenharmony_ci struct sk_buff *resp) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci int rc; 7468c2ecf20Sopenharmony_ci u8 proto; 7478c2ecf20Sopenharmony_ci struct nfc_target target; 7488c2ecf20Sopenharmony_ci struct digital_sensf_res *sensf_res; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 7518c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 7528c2ecf20Sopenharmony_ci resp = NULL; 7538c2ecf20Sopenharmony_ci goto exit; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (resp->len < DIGITAL_SENSF_RES_MIN_LENGTH) { 7578c2ecf20Sopenharmony_ci rc = -EIO; 7588c2ecf20Sopenharmony_ci goto exit; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) { 7628c2ecf20Sopenharmony_ci rc = digital_skb_check_crc_f(resp); 7638c2ecf20Sopenharmony_ci if (rc) { 7648c2ecf20Sopenharmony_ci PROTOCOL_ERR("6.4.1.8"); 7658c2ecf20Sopenharmony_ci goto exit; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci skb_pull(resp, 1); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci memset(&target, 0, sizeof(struct nfc_target)); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci sensf_res = (struct digital_sensf_res *)resp->data; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci memcpy(target.sensf_res, sensf_res, resp->len); 7768c2ecf20Sopenharmony_ci target.sensf_res_len = resp->len; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci memcpy(target.nfcid2, sensf_res->nfcid2, NFC_NFCID2_MAXSIZE); 7798c2ecf20Sopenharmony_ci target.nfcid2_len = NFC_NFCID2_MAXSIZE; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (target.nfcid2[0] == DIGITAL_SENSF_NFCID2_NFC_DEP_B1 && 7828c2ecf20Sopenharmony_ci target.nfcid2[1] == DIGITAL_SENSF_NFCID2_NFC_DEP_B2) 7838c2ecf20Sopenharmony_ci proto = NFC_PROTO_NFC_DEP; 7848c2ecf20Sopenharmony_ci else 7858c2ecf20Sopenharmony_ci proto = NFC_PROTO_FELICA; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci rc = digital_target_found(ddev, &target, proto); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ciexit: 7908c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (rc) 7938c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ciint digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct digital_sensf_req *sensf_req; 7998c2ecf20Sopenharmony_ci struct sk_buff *skb; 8008c2ecf20Sopenharmony_ci int rc; 8018c2ecf20Sopenharmony_ci u8 size; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); 8048c2ecf20Sopenharmony_ci if (rc) 8058c2ecf20Sopenharmony_ci return rc; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 8088c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCF); 8098c2ecf20Sopenharmony_ci if (rc) 8108c2ecf20Sopenharmony_ci return rc; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci size = sizeof(struct digital_sensf_req); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, size); 8158c2ecf20Sopenharmony_ci if (!skb) 8168c2ecf20Sopenharmony_ci return -ENOMEM; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci skb_put(skb, size); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci sensf_req = (struct digital_sensf_req *)skb->data; 8218c2ecf20Sopenharmony_ci sensf_req->cmd = DIGITAL_CMD_SENSF_REQ; 8228c2ecf20Sopenharmony_ci sensf_req->sc1 = 0xFF; 8238c2ecf20Sopenharmony_ci sensf_req->sc2 = 0xFF; 8248c2ecf20Sopenharmony_ci sensf_req->rc = 0; 8258c2ecf20Sopenharmony_ci sensf_req->tsn = 0; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = size + 1; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) 8308c2ecf20Sopenharmony_ci digital_skb_add_crc_f(skb); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sensf_res, 8338c2ecf20Sopenharmony_ci NULL); 8348c2ecf20Sopenharmony_ci if (rc) 8358c2ecf20Sopenharmony_ci kfree_skb(skb); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return rc; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic void digital_in_recv_iso15693_inv_res(struct nfc_digital_dev *ddev, 8418c2ecf20Sopenharmony_ci void *arg, struct sk_buff *resp) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct digital_iso15693_inv_res *res; 8448c2ecf20Sopenharmony_ci struct nfc_target *target = NULL; 8458c2ecf20Sopenharmony_ci int rc; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 8488c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 8498c2ecf20Sopenharmony_ci resp = NULL; 8508c2ecf20Sopenharmony_ci goto out_free_skb; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (resp->len != sizeof(*res)) { 8548c2ecf20Sopenharmony_ci rc = -EIO; 8558c2ecf20Sopenharmony_ci goto out_free_skb; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci res = (struct digital_iso15693_inv_res *)resp->data; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (!DIGITAL_ISO15693_RES_IS_VALID(res->flags)) { 8618c2ecf20Sopenharmony_ci PROTOCOL_ERR("ISO15693 - 10.3.1"); 8628c2ecf20Sopenharmony_ci rc = -EINVAL; 8638c2ecf20Sopenharmony_ci goto out_free_skb; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci target = kzalloc(sizeof(*target), GFP_KERNEL); 8678c2ecf20Sopenharmony_ci if (!target) { 8688c2ecf20Sopenharmony_ci rc = -ENOMEM; 8698c2ecf20Sopenharmony_ci goto out_free_skb; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci target->is_iso15693 = 1; 8738c2ecf20Sopenharmony_ci target->iso15693_dsfid = res->dsfid; 8748c2ecf20Sopenharmony_ci memcpy(target->iso15693_uid, &res->uid, sizeof(target->iso15693_uid)); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci rc = digital_target_found(ddev, target, NFC_PROTO_ISO15693); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci kfree(target); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ciout_free_skb: 8818c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (rc) 8848c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ciint digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct digital_iso15693_inv_req *req; 8908c2ecf20Sopenharmony_ci struct sk_buff *skb; 8918c2ecf20Sopenharmony_ci int rc; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, 8948c2ecf20Sopenharmony_ci NFC_DIGITAL_RF_TECH_ISO15693); 8958c2ecf20Sopenharmony_ci if (rc) 8968c2ecf20Sopenharmony_ci return rc; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 8998c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_ISO15693_INVENTORY); 9008c2ecf20Sopenharmony_ci if (rc) 9018c2ecf20Sopenharmony_ci return rc; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(*req)); 9048c2ecf20Sopenharmony_ci if (!skb) 9058c2ecf20Sopenharmony_ci return -ENOMEM; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci skb_put(skb, sizeof(*req) - sizeof(req->mask)); /* No mask */ 9088c2ecf20Sopenharmony_ci req = (struct digital_iso15693_inv_req *)skb->data; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Single sub-carrier, high data rate, no AFI, single slot 9118c2ecf20Sopenharmony_ci * Inventory command 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_ci req->flags = DIGITAL_ISO15693_REQ_FLAG_DATA_RATE | 9148c2ecf20Sopenharmony_ci DIGITAL_ISO15693_REQ_FLAG_INVENTORY | 9158c2ecf20Sopenharmony_ci DIGITAL_ISO15693_REQ_FLAG_NB_SLOTS; 9168c2ecf20Sopenharmony_ci req->cmd = DIGITAL_CMD_ISO15693_INVENTORY_REQ; 9178c2ecf20Sopenharmony_ci req->mask_len = 0; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, 30, 9208c2ecf20Sopenharmony_ci digital_in_recv_iso15693_inv_res, NULL); 9218c2ecf20Sopenharmony_ci if (rc) 9228c2ecf20Sopenharmony_ci kfree_skb(skb); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci return rc; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci struct sk_buff *skb; 9308c2ecf20Sopenharmony_ci int rc; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 9338c2ecf20Sopenharmony_ci if (!skb) 9348c2ecf20Sopenharmony_ci return -ENOMEM; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci skb_put_u8(skb, DIGITAL_SEL_RES_NFC_DEP); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) 9398c2ecf20Sopenharmony_ci digital_skb_add_crc_a(skb); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 9428c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE); 9438c2ecf20Sopenharmony_ci if (rc) { 9448c2ecf20Sopenharmony_ci kfree_skb(skb); 9458c2ecf20Sopenharmony_ci return rc; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req, 9498c2ecf20Sopenharmony_ci NULL); 9508c2ecf20Sopenharmony_ci if (rc) 9518c2ecf20Sopenharmony_ci kfree_skb(skb); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci return rc; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic void digital_tg_recv_sel_req(struct nfc_digital_dev *ddev, void *arg, 9578c2ecf20Sopenharmony_ci struct sk_buff *resp) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci int rc; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 9628c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 9638c2ecf20Sopenharmony_ci resp = NULL; 9648c2ecf20Sopenharmony_ci goto exit; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) { 9688c2ecf20Sopenharmony_ci rc = digital_skb_check_crc_a(resp); 9698c2ecf20Sopenharmony_ci if (rc) { 9708c2ecf20Sopenharmony_ci PROTOCOL_ERR("4.4.1.3"); 9718c2ecf20Sopenharmony_ci goto exit; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Silently ignore SEL_REQ content and send a SEL_RES for NFC-DEP */ 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci rc = digital_tg_send_sel_res(ddev); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ciexit: 9808c2ecf20Sopenharmony_ci if (rc) 9818c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int digital_tg_send_sdd_res(struct nfc_digital_dev *ddev) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci struct sk_buff *skb; 9898c2ecf20Sopenharmony_ci struct digital_sdd_res *sdd_res; 9908c2ecf20Sopenharmony_ci int rc, i; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(struct digital_sdd_res)); 9938c2ecf20Sopenharmony_ci if (!skb) 9948c2ecf20Sopenharmony_ci return -ENOMEM; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci skb_put(skb, sizeof(struct digital_sdd_res)); 9978c2ecf20Sopenharmony_ci sdd_res = (struct digital_sdd_res *)skb->data; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci sdd_res->nfcid1[0] = 0x08; 10008c2ecf20Sopenharmony_ci get_random_bytes(sdd_res->nfcid1 + 1, 3); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci sdd_res->bcc = 0; 10038c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 10048c2ecf20Sopenharmony_ci sdd_res->bcc ^= sdd_res->nfcid1[i]; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 10078c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A); 10088c2ecf20Sopenharmony_ci if (rc) { 10098c2ecf20Sopenharmony_ci kfree_skb(skb); 10108c2ecf20Sopenharmony_ci return rc; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req, 10148c2ecf20Sopenharmony_ci NULL); 10158c2ecf20Sopenharmony_ci if (rc) 10168c2ecf20Sopenharmony_ci kfree_skb(skb); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return rc; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic void digital_tg_recv_sdd_req(struct nfc_digital_dev *ddev, void *arg, 10228c2ecf20Sopenharmony_ci struct sk_buff *resp) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci u8 *sdd_req; 10258c2ecf20Sopenharmony_ci int rc; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 10288c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 10298c2ecf20Sopenharmony_ci resp = NULL; 10308c2ecf20Sopenharmony_ci goto exit; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci sdd_req = resp->data; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (resp->len < 2 || sdd_req[0] != DIGITAL_CMD_SEL_REQ_CL1 || 10368c2ecf20Sopenharmony_ci sdd_req[1] != DIGITAL_SDD_REQ_SEL_PAR) { 10378c2ecf20Sopenharmony_ci rc = -EINVAL; 10388c2ecf20Sopenharmony_ci goto exit; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci rc = digital_tg_send_sdd_res(ddev); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ciexit: 10448c2ecf20Sopenharmony_ci if (rc) 10458c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic int digital_tg_send_sens_res(struct nfc_digital_dev *ddev) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct sk_buff *skb; 10538c2ecf20Sopenharmony_ci u8 *sens_res; 10548c2ecf20Sopenharmony_ci int rc; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 2); 10578c2ecf20Sopenharmony_ci if (!skb) 10588c2ecf20Sopenharmony_ci return -ENOMEM; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci sens_res = skb_put(skb, 2); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF; 10638c2ecf20Sopenharmony_ci sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 10668c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_STANDARD); 10678c2ecf20Sopenharmony_ci if (rc) { 10688c2ecf20Sopenharmony_ci kfree_skb(skb); 10698c2ecf20Sopenharmony_ci return rc; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req, 10738c2ecf20Sopenharmony_ci NULL); 10748c2ecf20Sopenharmony_ci if (rc) 10758c2ecf20Sopenharmony_ci kfree_skb(skb); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return rc; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_civoid digital_tg_recv_sens_req(struct nfc_digital_dev *ddev, void *arg, 10818c2ecf20Sopenharmony_ci struct sk_buff *resp) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci u8 sens_req; 10848c2ecf20Sopenharmony_ci int rc; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 10878c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 10888c2ecf20Sopenharmony_ci resp = NULL; 10898c2ecf20Sopenharmony_ci goto exit; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci sens_req = resp->data[0]; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (!resp->len || (sens_req != DIGITAL_CMD_SENS_REQ && 10958c2ecf20Sopenharmony_ci sens_req != DIGITAL_CMD_ALL_REQ)) { 10968c2ecf20Sopenharmony_ci rc = -EINVAL; 10978c2ecf20Sopenharmony_ci goto exit; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci rc = digital_tg_send_sens_res(ddev); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ciexit: 11038c2ecf20Sopenharmony_ci if (rc) 11048c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic void digital_tg_recv_atr_or_sensf_req(struct nfc_digital_dev *ddev, 11108c2ecf20Sopenharmony_ci void *arg, struct sk_buff *resp) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci if (!IS_ERR(resp) && (resp->len >= 2) && 11138c2ecf20Sopenharmony_ci (resp->data[1] == DIGITAL_CMD_SENSF_REQ)) 11148c2ecf20Sopenharmony_ci digital_tg_recv_sensf_req(ddev, arg, resp); 11158c2ecf20Sopenharmony_ci else 11168c2ecf20Sopenharmony_ci digital_tg_recv_atr_req(ddev, arg, resp); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic int digital_tg_send_sensf_res(struct nfc_digital_dev *ddev, 11228c2ecf20Sopenharmony_ci struct digital_sensf_req *sensf_req) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci struct sk_buff *skb; 11258c2ecf20Sopenharmony_ci u8 size; 11268c2ecf20Sopenharmony_ci int rc; 11278c2ecf20Sopenharmony_ci struct digital_sensf_res *sensf_res; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci size = sizeof(struct digital_sensf_res); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (sensf_req->rc == DIGITAL_SENSF_REQ_RC_NONE) 11328c2ecf20Sopenharmony_ci size -= sizeof(sensf_res->rd); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, size); 11358c2ecf20Sopenharmony_ci if (!skb) 11368c2ecf20Sopenharmony_ci return -ENOMEM; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci skb_put(skb, size); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci sensf_res = (struct digital_sensf_res *)skb->data; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci memset(sensf_res, 0, size); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci sensf_res->cmd = DIGITAL_CMD_SENSF_RES; 11458c2ecf20Sopenharmony_ci sensf_res->nfcid2[0] = DIGITAL_SENSF_NFCID2_NFC_DEP_B1; 11468c2ecf20Sopenharmony_ci sensf_res->nfcid2[1] = DIGITAL_SENSF_NFCID2_NFC_DEP_B2; 11478c2ecf20Sopenharmony_ci get_random_bytes(&sensf_res->nfcid2[2], 6); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci switch (sensf_req->rc) { 11508c2ecf20Sopenharmony_ci case DIGITAL_SENSF_REQ_RC_SC: 11518c2ecf20Sopenharmony_ci sensf_res->rd[0] = sensf_req->sc1; 11528c2ecf20Sopenharmony_ci sensf_res->rd[1] = sensf_req->sc2; 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci case DIGITAL_SENSF_REQ_RC_AP: 11558c2ecf20Sopenharmony_ci sensf_res->rd[0] = DIGITAL_SENSF_RES_RD_AP_B1; 11568c2ecf20Sopenharmony_ci sensf_res->rd[1] = DIGITAL_SENSF_RES_RD_AP_B2; 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, sizeof(u8)) = size + 1; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) 11638c2ecf20Sopenharmony_ci digital_skb_add_crc_f(skb); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 300, 11668c2ecf20Sopenharmony_ci digital_tg_recv_atr_or_sensf_req, NULL); 11678c2ecf20Sopenharmony_ci if (rc) 11688c2ecf20Sopenharmony_ci kfree_skb(skb); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return rc; 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_civoid digital_tg_recv_sensf_req(struct nfc_digital_dev *ddev, void *arg, 11748c2ecf20Sopenharmony_ci struct sk_buff *resp) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct digital_sensf_req *sensf_req; 11778c2ecf20Sopenharmony_ci int rc; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 11808c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 11818c2ecf20Sopenharmony_ci resp = NULL; 11828c2ecf20Sopenharmony_ci goto exit; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) { 11868c2ecf20Sopenharmony_ci rc = digital_skb_check_crc_f(resp); 11878c2ecf20Sopenharmony_ci if (rc) { 11888c2ecf20Sopenharmony_ci PROTOCOL_ERR("6.4.1.8"); 11898c2ecf20Sopenharmony_ci goto exit; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (resp->len != sizeof(struct digital_sensf_req) + 1) { 11948c2ecf20Sopenharmony_ci rc = -EINVAL; 11958c2ecf20Sopenharmony_ci goto exit; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci skb_pull(resp, 1); 11998c2ecf20Sopenharmony_ci sensf_req = (struct digital_sensf_req *)resp->data; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (sensf_req->cmd != DIGITAL_CMD_SENSF_REQ) { 12028c2ecf20Sopenharmony_ci rc = -EINVAL; 12038c2ecf20Sopenharmony_ci goto exit; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci rc = digital_tg_send_sensf_res(ddev, sensf_req); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ciexit: 12098c2ecf20Sopenharmony_ci if (rc) 12108c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int digital_tg_config_nfca(struct nfc_digital_dev *ddev) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci int rc; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, 12208c2ecf20Sopenharmony_ci NFC_DIGITAL_RF_TECH_106A); 12218c2ecf20Sopenharmony_ci if (rc) 12228c2ecf20Sopenharmony_ci return rc; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 12258c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ciint digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci int rc; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci rc = digital_tg_config_nfca(ddev); 12338c2ecf20Sopenharmony_ci if (rc) 12348c2ecf20Sopenharmony_ci return rc; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic int digital_tg_config_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci int rc; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); 12448c2ecf20Sopenharmony_ci if (rc) 12458c2ecf20Sopenharmony_ci return rc; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 12488c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ciint digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci int rc; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci rc = digital_tg_config_nfcf(ddev, rf_tech); 12568c2ecf20Sopenharmony_ci if (rc) 12578c2ecf20Sopenharmony_ci return rc; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, NULL); 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_civoid digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, 12638c2ecf20Sopenharmony_ci struct sk_buff *resp) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci u8 rf_tech; 12668c2ecf20Sopenharmony_ci int rc; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 12698c2ecf20Sopenharmony_ci resp = NULL; 12708c2ecf20Sopenharmony_ci goto exit_free_skb; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci rc = ddev->ops->tg_get_rf_tech(ddev, &rf_tech); 12748c2ecf20Sopenharmony_ci if (rc) 12758c2ecf20Sopenharmony_ci goto exit_free_skb; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci switch (rf_tech) { 12788c2ecf20Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106A: 12798c2ecf20Sopenharmony_ci rc = digital_tg_config_nfca(ddev); 12808c2ecf20Sopenharmony_ci if (rc) 12818c2ecf20Sopenharmony_ci goto exit_free_skb; 12828c2ecf20Sopenharmony_ci digital_tg_recv_sens_req(ddev, arg, resp); 12838c2ecf20Sopenharmony_ci break; 12848c2ecf20Sopenharmony_ci case NFC_DIGITAL_RF_TECH_212F: 12858c2ecf20Sopenharmony_ci case NFC_DIGITAL_RF_TECH_424F: 12868c2ecf20Sopenharmony_ci rc = digital_tg_config_nfcf(ddev, rf_tech); 12878c2ecf20Sopenharmony_ci if (rc) 12888c2ecf20Sopenharmony_ci goto exit_free_skb; 12898c2ecf20Sopenharmony_ci digital_tg_recv_sensf_req(ddev, arg, resp); 12908c2ecf20Sopenharmony_ci break; 12918c2ecf20Sopenharmony_ci default: 12928c2ecf20Sopenharmony_ci goto exit_free_skb; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ciexit_free_skb: 12988c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 12998c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 13008c2ecf20Sopenharmony_ci} 1301