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_NFC_DEP_N_RETRY_NACK 2 128c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_N_RETRY_ATN 2 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 158c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_NFCA_SOD_SB 0xF0 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define DIGITAL_CMD_ATR_REQ 0x00 208c2ecf20Sopenharmony_ci#define DIGITAL_CMD_ATR_RES 0x01 218c2ecf20Sopenharmony_ci#define DIGITAL_CMD_PSL_REQ 0x04 228c2ecf20Sopenharmony_ci#define DIGITAL_CMD_PSL_RES 0x05 238c2ecf20Sopenharmony_ci#define DIGITAL_CMD_DEP_REQ 0x06 248c2ecf20Sopenharmony_ci#define DIGITAL_CMD_DEP_RES 0x07 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DIGITAL_ATR_REQ_MIN_SIZE 16 278c2ecf20Sopenharmony_ci#define DIGITAL_ATR_REQ_MAX_SIZE 64 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define DIGITAL_ATR_RES_TO_WT(s) ((s) & 0xF) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define DIGITAL_DID_MAX 14 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define DIGITAL_PAYLOAD_SIZE_MAX 254 348c2ecf20Sopenharmony_ci#define DIGITAL_PAYLOAD_BITS_TO_PP(s) (((s) & 0x3) << 4) 358c2ecf20Sopenharmony_ci#define DIGITAL_PAYLOAD_PP_TO_BITS(s) (((s) >> 4) & 0x3) 368c2ecf20Sopenharmony_ci#define DIGITAL_PAYLOAD_BITS_TO_FSL(s) ((s) & 0x3) 378c2ecf20Sopenharmony_ci#define DIGITAL_PAYLOAD_FSL_TO_BITS(s) ((s) & 0x3) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define DIGITAL_GB_BIT 0x02 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT 0x10 448c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_MI_BIT 0x10 458c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_NACK_BIT 0x10 468c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_DID_BIT 0x04 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb) \ 498c2ecf20Sopenharmony_ci ((pfb) & DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT) 508c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_MI_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_MI_BIT) 518c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_NACK_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_NACK_BIT) 528c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08) 538c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_DID_BIT) 548c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_PNI(pfb) ((pfb) & 0x03) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_RTOX_VALUE(data) ((data) & 0x3F) 578c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_RTOX_MAX 59 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_I_PDU 0x00 608c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU 0x40 618c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU 0x80 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct digital_atr_req { 648c2ecf20Sopenharmony_ci u8 dir; 658c2ecf20Sopenharmony_ci u8 cmd; 668c2ecf20Sopenharmony_ci u8 nfcid3[10]; 678c2ecf20Sopenharmony_ci u8 did; 688c2ecf20Sopenharmony_ci u8 bs; 698c2ecf20Sopenharmony_ci u8 br; 708c2ecf20Sopenharmony_ci u8 pp; 718c2ecf20Sopenharmony_ci u8 gb[]; 728c2ecf20Sopenharmony_ci} __packed; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct digital_atr_res { 758c2ecf20Sopenharmony_ci u8 dir; 768c2ecf20Sopenharmony_ci u8 cmd; 778c2ecf20Sopenharmony_ci u8 nfcid3[10]; 788c2ecf20Sopenharmony_ci u8 did; 798c2ecf20Sopenharmony_ci u8 bs; 808c2ecf20Sopenharmony_ci u8 br; 818c2ecf20Sopenharmony_ci u8 to; 828c2ecf20Sopenharmony_ci u8 pp; 838c2ecf20Sopenharmony_ci u8 gb[]; 848c2ecf20Sopenharmony_ci} __packed; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct digital_psl_req { 878c2ecf20Sopenharmony_ci u8 dir; 888c2ecf20Sopenharmony_ci u8 cmd; 898c2ecf20Sopenharmony_ci u8 did; 908c2ecf20Sopenharmony_ci u8 brs; 918c2ecf20Sopenharmony_ci u8 fsl; 928c2ecf20Sopenharmony_ci} __packed; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct digital_psl_res { 958c2ecf20Sopenharmony_ci u8 dir; 968c2ecf20Sopenharmony_ci u8 cmd; 978c2ecf20Sopenharmony_ci u8 did; 988c2ecf20Sopenharmony_ci} __packed; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistruct digital_dep_req_res { 1018c2ecf20Sopenharmony_ci u8 dir; 1028c2ecf20Sopenharmony_ci u8 cmd; 1038c2ecf20Sopenharmony_ci u8 pfb; 1048c2ecf20Sopenharmony_ci} __packed; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, 1078c2ecf20Sopenharmony_ci struct sk_buff *resp); 1088c2ecf20Sopenharmony_cistatic void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, 1098c2ecf20Sopenharmony_ci struct sk_buff *resp); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const u8 digital_payload_bits_map[4] = { 1128c2ecf20Sopenharmony_ci [0] = 64, 1138c2ecf20Sopenharmony_ci [1] = 128, 1148c2ecf20Sopenharmony_ci [2] = 192, 1158c2ecf20Sopenharmony_ci [3] = 254 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Response Waiting Time for ATR_RES PDU in ms 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * RWT(ATR_RES) = RWT(nfcdep,activation) + dRWT(nfcdep) + dT(nfcdep,initiator) 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * with: 1238c2ecf20Sopenharmony_ci * RWT(nfcdep,activation) = 4096 * 2^12 / f(c) s 1248c2ecf20Sopenharmony_ci * dRWT(nfcdep) = 16 / f(c) s 1258c2ecf20Sopenharmony_ci * dT(nfcdep,initiator) = 100 ms 1268c2ecf20Sopenharmony_ci * f(c) = 13560000 Hz 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci#define DIGITAL_ATR_RES_RWT 1337 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Response Waiting Time for other DEP PDUs in ms 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * max_rwt = rwt + dRWT(nfcdep) + dT(nfcdep,initiator) 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * with: 1358c2ecf20Sopenharmony_ci * rwt = (256 * 16 / f(c)) * 2^wt s 1368c2ecf20Sopenharmony_ci * dRWT(nfcdep) = 16 / f(c) s 1378c2ecf20Sopenharmony_ci * dT(nfcdep,initiator) = 100 ms 1388c2ecf20Sopenharmony_ci * f(c) = 13560000 Hz 1398c2ecf20Sopenharmony_ci * 0 <= wt <= 14 (given by the target by the TO field of ATR_RES response) 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_IN_MAX_WT 14 1428c2ecf20Sopenharmony_ci#define DIGITAL_NFC_DEP_TG_MAX_WT 14 1438c2ecf20Sopenharmony_cistatic const u16 digital_rwt_map[DIGITAL_NFC_DEP_IN_MAX_WT + 1] = { 1448c2ecf20Sopenharmony_ci 100, 101, 101, 102, 105, 1458c2ecf20Sopenharmony_ci 110, 119, 139, 177, 255, 1468c2ecf20Sopenharmony_ci 409, 719, 1337, 2575, 5049, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic u8 digital_payload_bits_to_size(u8 payload_bits) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci if (payload_bits >= ARRAY_SIZE(digital_payload_bits_map)) 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return digital_payload_bits_map[payload_bits]; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic u8 digital_payload_size_to_bits(u8 payload_size) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(digital_payload_bits_map); i++) 1628c2ecf20Sopenharmony_ci if (digital_payload_bits_map[i] == payload_size) 1638c2ecf20Sopenharmony_ci return i; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0xff; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void digital_skb_push_dep_sod(struct nfc_digital_dev *ddev, 1698c2ecf20Sopenharmony_ci struct sk_buff *skb) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci skb_push(skb, sizeof(u8)); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci skb->data[0] = skb->len; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A) 1768c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, sizeof(u8)) = DIGITAL_NFC_DEP_NFCA_SOD_SB; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int digital_skb_pull_dep_sod(struct nfc_digital_dev *ddev, 1808c2ecf20Sopenharmony_ci struct sk_buff *skb) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u8 size; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (skb->len < 2) 1858c2ecf20Sopenharmony_ci return -EIO; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A) 1888c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(u8)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci size = skb->data[0]; 1918c2ecf20Sopenharmony_ci if (size != skb->len) 1928c2ecf20Sopenharmony_ci return -EIO; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(u8)); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic struct sk_buff * 2008c2ecf20Sopenharmony_cidigital_send_dep_data_prep(struct nfc_digital_dev *ddev, struct sk_buff *skb, 2018c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req_res, 2028c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct sk_buff *new_skb; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (skb->len > ddev->remote_payload_max) { 2078c2ecf20Sopenharmony_ci dep_req_res->pfb |= DIGITAL_NFC_DEP_PFB_MI_BIT; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci new_skb = digital_skb_alloc(ddev, ddev->remote_payload_max); 2108c2ecf20Sopenharmony_ci if (!new_skb) { 2118c2ecf20Sopenharmony_ci kfree_skb(ddev->chaining_skb); 2128c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci skb_put_data(new_skb, skb->data, ddev->remote_payload_max); 2188c2ecf20Sopenharmony_ci skb_pull(skb, ddev->remote_payload_max); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ddev->chaining_skb = skb; 2218c2ecf20Sopenharmony_ci ddev->data_exch = data_exch; 2228c2ecf20Sopenharmony_ci } else { 2238c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 2248c2ecf20Sopenharmony_ci new_skb = skb; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return new_skb; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic struct sk_buff * 2318c2ecf20Sopenharmony_cidigital_recv_dep_data_gather(struct nfc_digital_dev *ddev, u8 pfb, 2328c2ecf20Sopenharmony_ci struct sk_buff *resp, 2338c2ecf20Sopenharmony_ci int (*send_ack)(struct nfc_digital_dev *ddev, 2348c2ecf20Sopenharmony_ci struct digital_data_exch 2358c2ecf20Sopenharmony_ci *data_exch), 2368c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct sk_buff *new_skb; 2398c2ecf20Sopenharmony_ci int rc; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb) && (!ddev->chaining_skb)) { 2428c2ecf20Sopenharmony_ci ddev->chaining_skb = 2438c2ecf20Sopenharmony_ci nfc_alloc_recv_skb(8 * ddev->local_payload_max, 2448c2ecf20Sopenharmony_ci GFP_KERNEL); 2458c2ecf20Sopenharmony_ci if (!ddev->chaining_skb) { 2468c2ecf20Sopenharmony_ci rc = -ENOMEM; 2478c2ecf20Sopenharmony_ci goto error; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (ddev->chaining_skb) { 2528c2ecf20Sopenharmony_ci if (resp->len > skb_tailroom(ddev->chaining_skb)) { 2538c2ecf20Sopenharmony_ci new_skb = skb_copy_expand(ddev->chaining_skb, 2548c2ecf20Sopenharmony_ci skb_headroom( 2558c2ecf20Sopenharmony_ci ddev->chaining_skb), 2568c2ecf20Sopenharmony_ci 8 * ddev->local_payload_max, 2578c2ecf20Sopenharmony_ci GFP_KERNEL); 2588c2ecf20Sopenharmony_ci if (!new_skb) { 2598c2ecf20Sopenharmony_ci rc = -ENOMEM; 2608c2ecf20Sopenharmony_ci goto error; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci kfree_skb(ddev->chaining_skb); 2648c2ecf20Sopenharmony_ci ddev->chaining_skb = new_skb; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci skb_put_data(ddev->chaining_skb, resp->data, resp->len); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci kfree_skb(resp); 2708c2ecf20Sopenharmony_ci resp = NULL; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb)) { 2738c2ecf20Sopenharmony_ci rc = send_ack(ddev, data_exch); 2748c2ecf20Sopenharmony_ci if (rc) 2758c2ecf20Sopenharmony_ci goto error; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return NULL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci resp = ddev->chaining_skb; 2818c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return resp; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cierror: 2878c2ecf20Sopenharmony_ci kfree_skb(resp); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci kfree_skb(ddev->chaining_skb); 2908c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return ERR_PTR(rc); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg, 2968c2ecf20Sopenharmony_ci struct sk_buff *resp) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct nfc_target *target = arg; 2998c2ecf20Sopenharmony_ci struct digital_psl_res *psl_res; 3008c2ecf20Sopenharmony_ci int rc; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 3038c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 3048c2ecf20Sopenharmony_ci resp = NULL; 3058c2ecf20Sopenharmony_ci goto exit; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci rc = ddev->skb_check_crc(resp); 3098c2ecf20Sopenharmony_ci if (rc) { 3108c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.6"); 3118c2ecf20Sopenharmony_ci goto exit; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci rc = digital_skb_pull_dep_sod(ddev, resp); 3158c2ecf20Sopenharmony_ci if (rc) { 3168c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.2"); 3178c2ecf20Sopenharmony_ci goto exit; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci psl_res = (struct digital_psl_res *)resp->data; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if ((resp->len != sizeof(*psl_res)) || 3238c2ecf20Sopenharmony_ci (psl_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN) || 3248c2ecf20Sopenharmony_ci (psl_res->cmd != DIGITAL_CMD_PSL_RES)) { 3258c2ecf20Sopenharmony_ci rc = -EIO; 3268c2ecf20Sopenharmony_ci goto exit; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, 3308c2ecf20Sopenharmony_ci NFC_DIGITAL_RF_TECH_424F); 3318c2ecf20Sopenharmony_ci if (rc) 3328c2ecf20Sopenharmony_ci goto exit; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 3358c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); 3368c2ecf20Sopenharmony_ci if (rc) 3378c2ecf20Sopenharmony_ci goto exit; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!DIGITAL_DRV_CAPS_IN_CRC(ddev) && 3408c2ecf20Sopenharmony_ci (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A)) { 3418c2ecf20Sopenharmony_ci ddev->skb_add_crc = digital_skb_add_crc_f; 3428c2ecf20Sopenharmony_ci ddev->skb_check_crc = digital_skb_check_crc_f; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_424F; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE, 3488c2ecf20Sopenharmony_ci NFC_RF_INITIATOR); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciexit: 3538c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (rc) 3568c2ecf20Sopenharmony_ci ddev->curr_protocol = 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int digital_in_send_psl_req(struct nfc_digital_dev *ddev, 3608c2ecf20Sopenharmony_ci struct nfc_target *target) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct sk_buff *skb; 3638c2ecf20Sopenharmony_ci struct digital_psl_req *psl_req; 3648c2ecf20Sopenharmony_ci int rc; 3658c2ecf20Sopenharmony_ci u8 payload_size, payload_bits; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(*psl_req)); 3688c2ecf20Sopenharmony_ci if (!skb) 3698c2ecf20Sopenharmony_ci return -ENOMEM; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci skb_put(skb, sizeof(*psl_req)); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci psl_req = (struct digital_psl_req *)skb->data; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci psl_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 3768c2ecf20Sopenharmony_ci psl_req->cmd = DIGITAL_CMD_PSL_REQ; 3778c2ecf20Sopenharmony_ci psl_req->did = 0; 3788c2ecf20Sopenharmony_ci psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */ 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci payload_size = min(ddev->local_payload_max, ddev->remote_payload_max); 3818c2ecf20Sopenharmony_ci payload_bits = digital_payload_size_to_bits(payload_size); 3828c2ecf20Sopenharmony_ci psl_req->fsl = DIGITAL_PAYLOAD_BITS_TO_FSL(payload_bits); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci ddev->local_payload_max = payload_size; 3858c2ecf20Sopenharmony_ci ddev->remote_payload_max = payload_size; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, ddev->dep_rwt, 3928c2ecf20Sopenharmony_ci digital_in_recv_psl_res, target); 3938c2ecf20Sopenharmony_ci if (rc) 3948c2ecf20Sopenharmony_ci kfree_skb(skb); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return rc; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg, 4008c2ecf20Sopenharmony_ci struct sk_buff *resp) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct nfc_target *target = arg; 4038c2ecf20Sopenharmony_ci struct digital_atr_res *atr_res; 4048c2ecf20Sopenharmony_ci u8 gb_len, payload_bits; 4058c2ecf20Sopenharmony_ci u8 wt; 4068c2ecf20Sopenharmony_ci int rc; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 4098c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 4108c2ecf20Sopenharmony_ci resp = NULL; 4118c2ecf20Sopenharmony_ci goto exit; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci rc = ddev->skb_check_crc(resp); 4158c2ecf20Sopenharmony_ci if (rc) { 4168c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.6"); 4178c2ecf20Sopenharmony_ci goto exit; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci rc = digital_skb_pull_dep_sod(ddev, resp); 4218c2ecf20Sopenharmony_ci if (rc) { 4228c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.2"); 4238c2ecf20Sopenharmony_ci goto exit; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (resp->len < sizeof(struct digital_atr_res)) { 4278c2ecf20Sopenharmony_ci rc = -EIO; 4288c2ecf20Sopenharmony_ci goto exit; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci gb_len = resp->len - sizeof(struct digital_atr_res); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci atr_res = (struct digital_atr_res *)resp->data; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci wt = DIGITAL_ATR_RES_TO_WT(atr_res->to); 4368c2ecf20Sopenharmony_ci if (wt > DIGITAL_NFC_DEP_IN_MAX_WT) 4378c2ecf20Sopenharmony_ci wt = DIGITAL_NFC_DEP_IN_MAX_WT; 4388c2ecf20Sopenharmony_ci ddev->dep_rwt = digital_rwt_map[wt]; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci payload_bits = DIGITAL_PAYLOAD_PP_TO_BITS(atr_res->pp); 4418c2ecf20Sopenharmony_ci ddev->remote_payload_max = digital_payload_bits_to_size(payload_bits); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!ddev->remote_payload_max) { 4448c2ecf20Sopenharmony_ci rc = -EINVAL; 4458c2ecf20Sopenharmony_ci goto exit; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci rc = nfc_set_remote_general_bytes(ddev->nfc_dev, atr_res->gb, gb_len); 4498c2ecf20Sopenharmony_ci if (rc) 4508c2ecf20Sopenharmony_ci goto exit; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if ((ddev->protocols & NFC_PROTO_FELICA_MASK) && 4538c2ecf20Sopenharmony_ci (ddev->curr_rf_tech != NFC_DIGITAL_RF_TECH_424F)) { 4548c2ecf20Sopenharmony_ci rc = digital_in_send_psl_req(ddev, target); 4558c2ecf20Sopenharmony_ci if (!rc) 4568c2ecf20Sopenharmony_ci goto exit; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci rc = nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE, 4608c2ecf20Sopenharmony_ci NFC_RF_INITIATOR); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 0; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ciexit: 4658c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (rc) 4688c2ecf20Sopenharmony_ci ddev->curr_protocol = 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ciint digital_in_send_atr_req(struct nfc_digital_dev *ddev, 4728c2ecf20Sopenharmony_ci struct nfc_target *target, __u8 comm_mode, __u8 *gb, 4738c2ecf20Sopenharmony_ci size_t gb_len) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct sk_buff *skb; 4768c2ecf20Sopenharmony_ci struct digital_atr_req *atr_req; 4778c2ecf20Sopenharmony_ci uint size; 4788c2ecf20Sopenharmony_ci int rc; 4798c2ecf20Sopenharmony_ci u8 payload_bits; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (size > DIGITAL_ATR_REQ_MAX_SIZE) { 4848c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.6.1.1"); 4858c2ecf20Sopenharmony_ci return -EINVAL; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, size); 4898c2ecf20Sopenharmony_ci if (!skb) 4908c2ecf20Sopenharmony_ci return -ENOMEM; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci skb_put(skb, sizeof(struct digital_atr_req)); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci atr_req = (struct digital_atr_req *)skb->data; 4958c2ecf20Sopenharmony_ci memset(atr_req, 0, sizeof(struct digital_atr_req)); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci atr_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 4988c2ecf20Sopenharmony_ci atr_req->cmd = DIGITAL_CMD_ATR_REQ; 4998c2ecf20Sopenharmony_ci if (target->nfcid2_len) 5008c2ecf20Sopenharmony_ci memcpy(atr_req->nfcid3, target->nfcid2, NFC_NFCID2_MAXSIZE); 5018c2ecf20Sopenharmony_ci else 5028c2ecf20Sopenharmony_ci get_random_bytes(atr_req->nfcid3, NFC_NFCID3_MAXSIZE); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci atr_req->did = 0; 5058c2ecf20Sopenharmony_ci atr_req->bs = 0; 5068c2ecf20Sopenharmony_ci atr_req->br = 0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ddev->local_payload_max = DIGITAL_PAYLOAD_SIZE_MAX; 5098c2ecf20Sopenharmony_ci payload_bits = digital_payload_size_to_bits(ddev->local_payload_max); 5108c2ecf20Sopenharmony_ci atr_req->pp = DIGITAL_PAYLOAD_BITS_TO_PP(payload_bits); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (gb_len) { 5138c2ecf20Sopenharmony_ci atr_req->pp |= DIGITAL_GB_BIT; 5148c2ecf20Sopenharmony_ci skb_put_data(skb, gb, gb_len); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, DIGITAL_ATR_RES_RWT, 5228c2ecf20Sopenharmony_ci digital_in_recv_atr_res, target); 5238c2ecf20Sopenharmony_ci if (rc) 5248c2ecf20Sopenharmony_ci kfree_skb(skb); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return rc; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic int digital_in_send_ack(struct nfc_digital_dev *ddev, 5308c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req; 5338c2ecf20Sopenharmony_ci struct sk_buff *skb; 5348c2ecf20Sopenharmony_ci int rc; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 5378c2ecf20Sopenharmony_ci if (!skb) 5388c2ecf20Sopenharmony_ci return -ENOMEM; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci dep_req = (struct digital_dep_req_res *)skb->data; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 5458c2ecf20Sopenharmony_ci dep_req->cmd = DIGITAL_CMD_DEP_REQ; 5468c2ecf20Sopenharmony_ci dep_req->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | 5478c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ddev->saved_skb = pskb_copy(skb, GFP_KERNEL); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, ddev->dep_rwt, 5568c2ecf20Sopenharmony_ci digital_in_recv_dep_res, data_exch); 5578c2ecf20Sopenharmony_ci if (rc) { 5588c2ecf20Sopenharmony_ci kfree_skb(skb); 5598c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 5608c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return rc; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int digital_in_send_nack(struct nfc_digital_dev *ddev, 5678c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req; 5708c2ecf20Sopenharmony_ci struct sk_buff *skb; 5718c2ecf20Sopenharmony_ci int rc; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 5748c2ecf20Sopenharmony_ci if (!skb) 5758c2ecf20Sopenharmony_ci return -ENOMEM; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dep_req = (struct digital_dep_req_res *)skb->data; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 5828c2ecf20Sopenharmony_ci dep_req->cmd = DIGITAL_CMD_DEP_REQ; 5838c2ecf20Sopenharmony_ci dep_req->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | 5848c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_NACK_BIT | ddev->curr_nfc_dep_pni; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, ddev->dep_rwt, 5918c2ecf20Sopenharmony_ci digital_in_recv_dep_res, data_exch); 5928c2ecf20Sopenharmony_ci if (rc) 5938c2ecf20Sopenharmony_ci kfree_skb(skb); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return rc; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int digital_in_send_atn(struct nfc_digital_dev *ddev, 5998c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req; 6028c2ecf20Sopenharmony_ci struct sk_buff *skb; 6038c2ecf20Sopenharmony_ci int rc; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 6068c2ecf20Sopenharmony_ci if (!skb) 6078c2ecf20Sopenharmony_ci return -ENOMEM; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci dep_req = (struct digital_dep_req_res *)skb->data; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 6148c2ecf20Sopenharmony_ci dep_req->cmd = DIGITAL_CMD_DEP_REQ; 6158c2ecf20Sopenharmony_ci dep_req->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, ddev->dep_rwt, 6228c2ecf20Sopenharmony_ci digital_in_recv_dep_res, data_exch); 6238c2ecf20Sopenharmony_ci if (rc) 6248c2ecf20Sopenharmony_ci kfree_skb(skb); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return rc; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int digital_in_send_rtox(struct nfc_digital_dev *ddev, 6308c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch, u8 rtox) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req; 6338c2ecf20Sopenharmony_ci struct sk_buff *skb; 6348c2ecf20Sopenharmony_ci int rc; 6358c2ecf20Sopenharmony_ci u16 rwt_int; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci rwt_int = ddev->dep_rwt * rtox; 6388c2ecf20Sopenharmony_ci if (rwt_int > digital_rwt_map[DIGITAL_NFC_DEP_IN_MAX_WT]) 6398c2ecf20Sopenharmony_ci rwt_int = digital_rwt_map[DIGITAL_NFC_DEP_IN_MAX_WT]; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 6428c2ecf20Sopenharmony_ci if (!skb) 6438c2ecf20Sopenharmony_ci return -ENOMEM; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci skb_put_u8(skb, rtox); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci dep_req = (struct digital_dep_req_res *)skb->data; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 6528c2ecf20Sopenharmony_ci dep_req->cmd = DIGITAL_CMD_DEP_REQ; 6538c2ecf20Sopenharmony_ci dep_req->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU | 6548c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, skb, rwt_int, 6618c2ecf20Sopenharmony_ci digital_in_recv_dep_res, data_exch); 6628c2ecf20Sopenharmony_ci if (rc) 6638c2ecf20Sopenharmony_ci kfree_skb(skb); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return rc; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic int digital_in_send_saved_skb(struct nfc_digital_dev *ddev, 6698c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci int rc; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (!ddev->saved_skb) 6748c2ecf20Sopenharmony_ci return -EINVAL; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci skb_get(ddev->saved_skb); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, ddev->saved_skb, ddev->dep_rwt, 6798c2ecf20Sopenharmony_ci digital_in_recv_dep_res, data_exch); 6808c2ecf20Sopenharmony_ci if (rc) 6818c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return rc; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, 6878c2ecf20Sopenharmony_ci struct sk_buff *resp) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch = arg; 6908c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_res; 6918c2ecf20Sopenharmony_ci u8 pfb; 6928c2ecf20Sopenharmony_ci uint size; 6938c2ecf20Sopenharmony_ci int rc; 6948c2ecf20Sopenharmony_ci u8 rtox; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 6978c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 6988c2ecf20Sopenharmony_ci resp = NULL; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if ((rc == -EIO || (rc == -ETIMEDOUT && ddev->nack_count)) && 7018c2ecf20Sopenharmony_ci (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { 7028c2ecf20Sopenharmony_ci ddev->atn_count = 0; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci rc = digital_in_send_nack(ddev, data_exch); 7058c2ecf20Sopenharmony_ci if (rc) 7068c2ecf20Sopenharmony_ci goto error; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return; 7098c2ecf20Sopenharmony_ci } else if ((rc == -ETIMEDOUT) && 7108c2ecf20Sopenharmony_ci (ddev->atn_count++ < DIGITAL_NFC_DEP_N_RETRY_ATN)) { 7118c2ecf20Sopenharmony_ci ddev->nack_count = 0; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci rc = digital_in_send_atn(ddev, data_exch); 7148c2ecf20Sopenharmony_ci if (rc) 7158c2ecf20Sopenharmony_ci goto error; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci goto exit; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci rc = digital_skb_pull_dep_sod(ddev, resp); 7248c2ecf20Sopenharmony_ci if (rc) { 7258c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.2"); 7268c2ecf20Sopenharmony_ci goto exit; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci rc = ddev->skb_check_crc(resp); 7308c2ecf20Sopenharmony_ci if (rc) { 7318c2ecf20Sopenharmony_ci if ((resp->len >= 4) && 7328c2ecf20Sopenharmony_ci (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { 7338c2ecf20Sopenharmony_ci ddev->atn_count = 0; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci rc = digital_in_send_nack(ddev, data_exch); 7368c2ecf20Sopenharmony_ci if (rc) 7378c2ecf20Sopenharmony_ci goto error; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci kfree_skb(resp); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.6"); 7458c2ecf20Sopenharmony_ci goto error; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci ddev->atn_count = 0; 7498c2ecf20Sopenharmony_ci ddev->nack_count = 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (resp->len > ddev->local_payload_max) { 7528c2ecf20Sopenharmony_ci rc = -EMSGSIZE; 7538c2ecf20Sopenharmony_ci goto exit; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci size = sizeof(struct digital_dep_req_res); 7578c2ecf20Sopenharmony_ci dep_res = (struct digital_dep_req_res *)resp->data; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (resp->len < size || dep_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN || 7608c2ecf20Sopenharmony_ci dep_res->cmd != DIGITAL_CMD_DEP_RES) { 7618c2ecf20Sopenharmony_ci rc = -EIO; 7628c2ecf20Sopenharmony_ci goto error; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci pfb = dep_res->pfb; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) { 7688c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.8.2.1"); 7698c2ecf20Sopenharmony_ci rc = -EIO; 7708c2ecf20Sopenharmony_ci goto error; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_NAD_BIT_SET(pfb)) { 7748c2ecf20Sopenharmony_ci rc = -EIO; 7758c2ecf20Sopenharmony_ci goto exit; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (size > resp->len) { 7798c2ecf20Sopenharmony_ci rc = -EIO; 7808c2ecf20Sopenharmony_ci goto error; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci skb_pull(resp, size); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) { 7868c2ecf20Sopenharmony_ci case DIGITAL_NFC_DEP_PFB_I_PDU: 7878c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { 7888c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.12.3.3"); 7898c2ecf20Sopenharmony_ci rc = -EIO; 7908c2ecf20Sopenharmony_ci goto error; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 7948c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 7978c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci resp = digital_recv_dep_data_gather(ddev, pfb, resp, 8008c2ecf20Sopenharmony_ci digital_in_send_ack, 8018c2ecf20Sopenharmony_ci data_exch); 8028c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 8038c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 8048c2ecf20Sopenharmony_ci resp = NULL; 8058c2ecf20Sopenharmony_ci goto error; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* If resp is NULL then we're still chaining so return and 8098c2ecf20Sopenharmony_ci * wait for the next part of the PDU. Else, the PDU is 8108c2ecf20Sopenharmony_ci * complete so pass it up. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci if (!resp) 8138c2ecf20Sopenharmony_ci return; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci rc = 0; 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: 8198c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { 8208c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.12.4.5"); 8218c2ecf20Sopenharmony_ci rc = -EIO; 8228c2ecf20Sopenharmony_ci goto exit; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { 8268c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.12.3.3"); 8278c2ecf20Sopenharmony_ci rc = -EIO; 8288c2ecf20Sopenharmony_ci goto exit; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 8328c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (!ddev->chaining_skb) { 8358c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.12.4.3"); 8368c2ecf20Sopenharmony_ci rc = -EIO; 8378c2ecf20Sopenharmony_ci goto exit; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* The initiator has received a valid ACK. Free the last sent 8418c2ecf20Sopenharmony_ci * PDU and keep on sending chained skb. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 8448c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci rc = digital_in_send_dep_req(ddev, NULL, 8478c2ecf20Sopenharmony_ci ddev->chaining_skb, 8488c2ecf20Sopenharmony_ci ddev->data_exch); 8498c2ecf20Sopenharmony_ci if (rc) 8508c2ecf20Sopenharmony_ci goto error; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci goto free_resp; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: 8558c2ecf20Sopenharmony_ci if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { /* ATN */ 8568c2ecf20Sopenharmony_ci rc = digital_in_send_saved_skb(ddev, data_exch); 8578c2ecf20Sopenharmony_ci if (rc) 8588c2ecf20Sopenharmony_ci goto error; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci goto free_resp; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (ddev->atn_count || ddev->nack_count) { 8648c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.12.4.4"); 8658c2ecf20Sopenharmony_ci rc = -EIO; 8668c2ecf20Sopenharmony_ci goto error; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci rtox = DIGITAL_NFC_DEP_RTOX_VALUE(resp->data[0]); 8708c2ecf20Sopenharmony_ci if (!rtox || rtox > DIGITAL_NFC_DEP_RTOX_MAX) { 8718c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.8.4.1"); 8728c2ecf20Sopenharmony_ci rc = -EIO; 8738c2ecf20Sopenharmony_ci goto error; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci rc = digital_in_send_rtox(ddev, data_exch, rtox); 8778c2ecf20Sopenharmony_ci if (rc) 8788c2ecf20Sopenharmony_ci goto error; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci goto free_resp; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ciexit: 8848c2ecf20Sopenharmony_ci data_exch->cb(data_exch->cb_context, resp, rc); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cierror: 8878c2ecf20Sopenharmony_ci kfree(data_exch); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci kfree_skb(ddev->chaining_skb); 8908c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 8938c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (rc) 8968c2ecf20Sopenharmony_ci kfree_skb(resp); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci return; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cifree_resp: 9018c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ciint digital_in_send_dep_req(struct nfc_digital_dev *ddev, 9058c2ecf20Sopenharmony_ci struct nfc_target *target, struct sk_buff *skb, 9068c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req; 9098c2ecf20Sopenharmony_ci struct sk_buff *chaining_skb, *tmp_skb; 9108c2ecf20Sopenharmony_ci int rc; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci dep_req = (struct digital_dep_req_res *)skb->data; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 9178c2ecf20Sopenharmony_ci dep_req->cmd = DIGITAL_CMD_DEP_REQ; 9188c2ecf20Sopenharmony_ci dep_req->pfb = ddev->curr_nfc_dep_pni; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci ddev->atn_count = 0; 9218c2ecf20Sopenharmony_ci ddev->nack_count = 0; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci chaining_skb = ddev->chaining_skb; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci tmp_skb = digital_send_dep_data_prep(ddev, skb, dep_req, data_exch); 9268c2ecf20Sopenharmony_ci if (IS_ERR(tmp_skb)) 9278c2ecf20Sopenharmony_ci return PTR_ERR(tmp_skb); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, tmp_skb); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci ddev->skb_add_crc(tmp_skb); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci ddev->saved_skb = pskb_copy(tmp_skb, GFP_KERNEL); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci rc = digital_in_send_cmd(ddev, tmp_skb, ddev->dep_rwt, 9368c2ecf20Sopenharmony_ci digital_in_recv_dep_res, data_exch); 9378c2ecf20Sopenharmony_ci if (rc) { 9388c2ecf20Sopenharmony_ci if (tmp_skb != skb) 9398c2ecf20Sopenharmony_ci kfree_skb(tmp_skb); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci kfree_skb(chaining_skb); 9428c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 9458c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return rc; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci ddev->curr_rf_tech = rf_tech; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci ddev->skb_add_crc = digital_skb_add_crc_none; 9568c2ecf20Sopenharmony_ci ddev->skb_check_crc = digital_skb_check_crc_none; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) 9598c2ecf20Sopenharmony_ci return; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci switch (ddev->curr_rf_tech) { 9628c2ecf20Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106A: 9638c2ecf20Sopenharmony_ci ddev->skb_add_crc = digital_skb_add_crc_a; 9648c2ecf20Sopenharmony_ci ddev->skb_check_crc = digital_skb_check_crc_a; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci case NFC_DIGITAL_RF_TECH_212F: 9688c2ecf20Sopenharmony_ci case NFC_DIGITAL_RF_TECH_424F: 9698c2ecf20Sopenharmony_ci ddev->skb_add_crc = digital_skb_add_crc_f; 9708c2ecf20Sopenharmony_ci ddev->skb_check_crc = digital_skb_check_crc_f; 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci default: 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic int digital_tg_send_ack(struct nfc_digital_dev *ddev, 9798c2ecf20Sopenharmony_ci struct digital_data_exch *data_exch) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_res; 9828c2ecf20Sopenharmony_ci struct sk_buff *skb; 9838c2ecf20Sopenharmony_ci int rc; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 9868c2ecf20Sopenharmony_ci if (!skb) 9878c2ecf20Sopenharmony_ci return -ENOMEM; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci dep_res = (struct digital_dep_req_res *)skb->data; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; 9948c2ecf20Sopenharmony_ci dep_res->cmd = DIGITAL_CMD_DEP_RES; 9958c2ecf20Sopenharmony_ci dep_res->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | 9968c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (ddev->did) { 9998c2ecf20Sopenharmony_ci dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci skb_put_data(skb, &ddev->did, sizeof(ddev->did)); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 10058c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci ddev->saved_skb = pskb_copy(skb, GFP_KERNEL); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, 10148c2ecf20Sopenharmony_ci data_exch); 10158c2ecf20Sopenharmony_ci if (rc) { 10168c2ecf20Sopenharmony_ci kfree_skb(skb); 10178c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 10188c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci return rc; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic int digital_tg_send_atn(struct nfc_digital_dev *ddev) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_res; 10278c2ecf20Sopenharmony_ci struct sk_buff *skb; 10288c2ecf20Sopenharmony_ci int rc; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, 1); 10318c2ecf20Sopenharmony_ci if (!skb) 10328c2ecf20Sopenharmony_ci return -ENOMEM; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci dep_res = (struct digital_dep_req_res *)skb->data; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; 10398c2ecf20Sopenharmony_ci dep_res->cmd = DIGITAL_CMD_DEP_RES; 10408c2ecf20Sopenharmony_ci dep_res->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (ddev->did) { 10438c2ecf20Sopenharmony_ci dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci skb_put_data(skb, &ddev->did, sizeof(ddev->did)); 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, 10538c2ecf20Sopenharmony_ci NULL); 10548c2ecf20Sopenharmony_ci if (rc) 10558c2ecf20Sopenharmony_ci kfree_skb(skb); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return rc; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic int digital_tg_send_saved_skb(struct nfc_digital_dev *ddev) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci int rc; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (!ddev->saved_skb) 10658c2ecf20Sopenharmony_ci return -EINVAL; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci skb_get(ddev->saved_skb); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, ddev->saved_skb, 1500, 10708c2ecf20Sopenharmony_ci digital_tg_recv_dep_req, NULL); 10718c2ecf20Sopenharmony_ci if (rc) 10728c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci return rc; 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, 10788c2ecf20Sopenharmony_ci struct sk_buff *resp) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci int rc; 10818c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_req; 10828c2ecf20Sopenharmony_ci u8 pfb; 10838c2ecf20Sopenharmony_ci size_t size; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 10868c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 10878c2ecf20Sopenharmony_ci resp = NULL; 10888c2ecf20Sopenharmony_ci goto exit; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci rc = ddev->skb_check_crc(resp); 10928c2ecf20Sopenharmony_ci if (rc) { 10938c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.6"); 10948c2ecf20Sopenharmony_ci goto exit; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci rc = digital_skb_pull_dep_sod(ddev, resp); 10988c2ecf20Sopenharmony_ci if (rc) { 10998c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.2"); 11008c2ecf20Sopenharmony_ci goto exit; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (resp->len > ddev->local_payload_max) { 11048c2ecf20Sopenharmony_ci rc = -EMSGSIZE; 11058c2ecf20Sopenharmony_ci goto exit; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci size = sizeof(struct digital_dep_req_res); 11098c2ecf20Sopenharmony_ci dep_req = (struct digital_dep_req_res *)resp->data; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (resp->len < size || dep_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || 11128c2ecf20Sopenharmony_ci dep_req->cmd != DIGITAL_CMD_DEP_REQ) { 11138c2ecf20Sopenharmony_ci rc = -EIO; 11148c2ecf20Sopenharmony_ci goto exit; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci pfb = dep_req->pfb; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) { 11208c2ecf20Sopenharmony_ci if (ddev->did && (ddev->did == resp->data[3])) { 11218c2ecf20Sopenharmony_ci size++; 11228c2ecf20Sopenharmony_ci } else { 11238c2ecf20Sopenharmony_ci rc = -EIO; 11248c2ecf20Sopenharmony_ci goto exit; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci } else if (ddev->did) { 11278c2ecf20Sopenharmony_ci rc = -EIO; 11288c2ecf20Sopenharmony_ci goto exit; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_NAD_BIT_SET(pfb)) { 11328c2ecf20Sopenharmony_ci rc = -EIO; 11338c2ecf20Sopenharmony_ci goto exit; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (size > resp->len) { 11378c2ecf20Sopenharmony_ci rc = -EIO; 11388c2ecf20Sopenharmony_ci goto exit; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci skb_pull(resp, size); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) { 11448c2ecf20Sopenharmony_ci case DIGITAL_NFC_DEP_PFB_I_PDU: 11458c2ecf20Sopenharmony_ci pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (ddev->atn_count) { 11488c2ecf20Sopenharmony_ci /* The target has received (and replied to) at least one 11498c2ecf20Sopenharmony_ci * ATN DEP_REQ. 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_ci ddev->atn_count = 0; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* pni of resp PDU equal to the target current pni - 1 11548c2ecf20Sopenharmony_ci * means resp is the previous DEP_REQ PDU received from 11558c2ecf20Sopenharmony_ci * the initiator so the target replies with saved_skb 11568c2ecf20Sopenharmony_ci * which is the previous DEP_RES saved in 11578c2ecf20Sopenharmony_ci * digital_tg_send_dep_res(). 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_PNI(pfb) == 11608c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni - 1)) { 11618c2ecf20Sopenharmony_ci rc = digital_tg_send_saved_skb(ddev); 11628c2ecf20Sopenharmony_ci if (rc) 11638c2ecf20Sopenharmony_ci goto exit; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci goto free_resp; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* atn_count > 0 and PDU pni != curr_nfc_dep_pni - 1 11698c2ecf20Sopenharmony_ci * means the target probably did not received the last 11708c2ecf20Sopenharmony_ci * DEP_REQ PDU sent by the initiator. The target 11718c2ecf20Sopenharmony_ci * fallbacks to normal processing then. 11728c2ecf20Sopenharmony_ci */ 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { 11768c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.12.3.4"); 11778c2ecf20Sopenharmony_ci rc = -EIO; 11788c2ecf20Sopenharmony_ci goto exit; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 11828c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci resp = digital_recv_dep_data_gather(ddev, pfb, resp, 11858c2ecf20Sopenharmony_ci digital_tg_send_ack, NULL); 11868c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 11878c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 11888c2ecf20Sopenharmony_ci resp = NULL; 11898c2ecf20Sopenharmony_ci goto exit; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* If resp is NULL then we're still chaining so return and 11938c2ecf20Sopenharmony_ci * wait for the next part of the PDU. Else, the PDU is 11948c2ecf20Sopenharmony_ci * complete so pass it up. 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_ci if (!resp) 11978c2ecf20Sopenharmony_ci return; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci rc = 0; 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: 12028c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* NACK */ 12038c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) != 12048c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni) { 12058c2ecf20Sopenharmony_ci rc = -EIO; 12068c2ecf20Sopenharmony_ci goto exit; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ddev->atn_count = 0; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci rc = digital_tg_send_saved_skb(ddev); 12128c2ecf20Sopenharmony_ci if (rc) 12138c2ecf20Sopenharmony_ci goto exit; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci goto free_resp; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* ACK */ 12198c2ecf20Sopenharmony_ci if (ddev->atn_count) { 12208c2ecf20Sopenharmony_ci /* The target has previously recevied one or more ATN 12218c2ecf20Sopenharmony_ci * PDUs. 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_ci ddev->atn_count = 0; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci /* If the ACK PNI is equal to the target PNI - 1 means 12268c2ecf20Sopenharmony_ci * that the initiator did not receive the previous PDU 12278c2ecf20Sopenharmony_ci * sent by the target so re-send it. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) == 12308c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni) { 12318c2ecf20Sopenharmony_ci rc = digital_tg_send_saved_skb(ddev); 12328c2ecf20Sopenharmony_ci if (rc) 12338c2ecf20Sopenharmony_ci goto exit; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci goto free_resp; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* Otherwise, the target did not receive the previous 12398c2ecf20Sopenharmony_ci * ACK PDU from the initiator. Fallback to normal 12408c2ecf20Sopenharmony_ci * processing of chained PDU then. 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Keep on sending chained PDU */ 12458c2ecf20Sopenharmony_ci if (!ddev->chaining_skb || 12468c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_PNI(pfb) != 12478c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni) { 12488c2ecf20Sopenharmony_ci rc = -EIO; 12498c2ecf20Sopenharmony_ci goto exit; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 12538c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci rc = digital_tg_send_dep_res(ddev, ddev->chaining_skb); 12568c2ecf20Sopenharmony_ci if (rc) 12578c2ecf20Sopenharmony_ci goto exit; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci goto free_resp; 12608c2ecf20Sopenharmony_ci case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: 12618c2ecf20Sopenharmony_ci if (DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { 12628c2ecf20Sopenharmony_ci rc = -EINVAL; 12638c2ecf20Sopenharmony_ci goto exit; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci rc = digital_tg_send_atn(ddev); 12678c2ecf20Sopenharmony_ci if (rc) 12688c2ecf20Sopenharmony_ci goto exit; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci ddev->atn_count++; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci goto free_resp; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci rc = nfc_tm_data_received(ddev->nfc_dev, resp); 12768c2ecf20Sopenharmony_ci if (rc) 12778c2ecf20Sopenharmony_ci resp = NULL; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ciexit: 12808c2ecf20Sopenharmony_ci kfree_skb(ddev->chaining_skb); 12818c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci ddev->atn_count = 0; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 12868c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (rc) 12898c2ecf20Sopenharmony_ci kfree_skb(resp); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci return; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cifree_resp: 12948c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ciint digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct digital_dep_req_res *dep_res; 13008c2ecf20Sopenharmony_ci struct sk_buff *chaining_skb, *tmp_skb; 13018c2ecf20Sopenharmony_ci int rc; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci skb_push(skb, sizeof(struct digital_dep_req_res)); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci dep_res = (struct digital_dep_req_res *)skb->data; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; 13088c2ecf20Sopenharmony_ci dep_res->cmd = DIGITAL_CMD_DEP_RES; 13098c2ecf20Sopenharmony_ci dep_res->pfb = ddev->curr_nfc_dep_pni; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (ddev->did) { 13128c2ecf20Sopenharmony_ci dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci skb_put_data(skb, &ddev->did, sizeof(ddev->did)); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 13188c2ecf20Sopenharmony_ci DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci chaining_skb = ddev->chaining_skb; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci tmp_skb = digital_send_dep_data_prep(ddev, skb, dep_res, NULL); 13238c2ecf20Sopenharmony_ci if (IS_ERR(tmp_skb)) 13248c2ecf20Sopenharmony_ci return PTR_ERR(tmp_skb); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, tmp_skb); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci ddev->skb_add_crc(tmp_skb); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci ddev->saved_skb = pskb_copy(tmp_skb, GFP_KERNEL); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, tmp_skb, 1500, digital_tg_recv_dep_req, 13338c2ecf20Sopenharmony_ci NULL); 13348c2ecf20Sopenharmony_ci if (rc) { 13358c2ecf20Sopenharmony_ci if (tmp_skb != skb) 13368c2ecf20Sopenharmony_ci kfree_skb(tmp_skb); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci kfree_skb(chaining_skb); 13398c2ecf20Sopenharmony_ci ddev->chaining_skb = NULL; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci kfree_skb(ddev->saved_skb); 13428c2ecf20Sopenharmony_ci ddev->saved_skb = NULL; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci return rc; 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev, 13498c2ecf20Sopenharmony_ci void *arg, struct sk_buff *resp) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci u8 rf_tech = (unsigned long)arg; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci if (IS_ERR(resp)) 13548c2ecf20Sopenharmony_ci return; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci digital_tg_set_rf_tech(ddev, rf_tech); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cistatic int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did, 13668c2ecf20Sopenharmony_ci u8 rf_tech) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct digital_psl_res *psl_res; 13698c2ecf20Sopenharmony_ci struct sk_buff *skb; 13708c2ecf20Sopenharmony_ci int rc; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(struct digital_psl_res)); 13738c2ecf20Sopenharmony_ci if (!skb) 13748c2ecf20Sopenharmony_ci return -ENOMEM; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci skb_put(skb, sizeof(struct digital_psl_res)); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci psl_res = (struct digital_psl_res *)skb->data; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci psl_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; 13818c2ecf20Sopenharmony_ci psl_res->cmd = DIGITAL_CMD_PSL_RES; 13828c2ecf20Sopenharmony_ci psl_res->did = did; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 0; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, 13918c2ecf20Sopenharmony_ci (void *)(unsigned long)rf_tech); 13928c2ecf20Sopenharmony_ci if (rc) 13938c2ecf20Sopenharmony_ci kfree_skb(skb); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci return rc; 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg, 13998c2ecf20Sopenharmony_ci struct sk_buff *resp) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci int rc; 14028c2ecf20Sopenharmony_ci struct digital_psl_req *psl_req; 14038c2ecf20Sopenharmony_ci u8 rf_tech; 14048c2ecf20Sopenharmony_ci u8 dsi, payload_size, payload_bits; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 14078c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 14088c2ecf20Sopenharmony_ci resp = NULL; 14098c2ecf20Sopenharmony_ci goto exit; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci rc = ddev->skb_check_crc(resp); 14138c2ecf20Sopenharmony_ci if (rc) { 14148c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.6"); 14158c2ecf20Sopenharmony_ci goto exit; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci rc = digital_skb_pull_dep_sod(ddev, resp); 14198c2ecf20Sopenharmony_ci if (rc) { 14208c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.2"); 14218c2ecf20Sopenharmony_ci goto exit; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci psl_req = (struct digital_psl_req *)resp->data; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (resp->len != sizeof(struct digital_psl_req) || 14278c2ecf20Sopenharmony_ci psl_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || 14288c2ecf20Sopenharmony_ci psl_req->cmd != DIGITAL_CMD_PSL_REQ) { 14298c2ecf20Sopenharmony_ci rc = -EIO; 14308c2ecf20Sopenharmony_ci goto exit; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci dsi = (psl_req->brs >> 3) & 0x07; 14348c2ecf20Sopenharmony_ci switch (dsi) { 14358c2ecf20Sopenharmony_ci case 0: 14368c2ecf20Sopenharmony_ci rf_tech = NFC_DIGITAL_RF_TECH_106A; 14378c2ecf20Sopenharmony_ci break; 14388c2ecf20Sopenharmony_ci case 1: 14398c2ecf20Sopenharmony_ci rf_tech = NFC_DIGITAL_RF_TECH_212F; 14408c2ecf20Sopenharmony_ci break; 14418c2ecf20Sopenharmony_ci case 2: 14428c2ecf20Sopenharmony_ci rf_tech = NFC_DIGITAL_RF_TECH_424F; 14438c2ecf20Sopenharmony_ci break; 14448c2ecf20Sopenharmony_ci default: 14458c2ecf20Sopenharmony_ci pr_err("Unsupported dsi value %d\n", dsi); 14468c2ecf20Sopenharmony_ci goto exit; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci payload_bits = DIGITAL_PAYLOAD_FSL_TO_BITS(psl_req->fsl); 14508c2ecf20Sopenharmony_ci payload_size = digital_payload_bits_to_size(payload_bits); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (!payload_size || (payload_size > min(ddev->local_payload_max, 14538c2ecf20Sopenharmony_ci ddev->remote_payload_max))) { 14548c2ecf20Sopenharmony_ci rc = -EINVAL; 14558c2ecf20Sopenharmony_ci goto exit; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci ddev->local_payload_max = payload_size; 14598c2ecf20Sopenharmony_ci ddev->remote_payload_max = payload_size; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ciexit: 14648c2ecf20Sopenharmony_ci kfree_skb(resp); 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic void digital_tg_send_atr_res_complete(struct nfc_digital_dev *ddev, 14688c2ecf20Sopenharmony_ci void *arg, struct sk_buff *resp) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci int offset; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 14738c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 14748c2ecf20Sopenharmony_ci return; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci offset = 2; 14788c2ecf20Sopenharmony_ci if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) 14798c2ecf20Sopenharmony_ci offset++; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci ddev->atn_count = 0; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (resp->data[offset] == DIGITAL_CMD_PSL_REQ) 14848c2ecf20Sopenharmony_ci digital_tg_recv_psl_req(ddev, arg, resp); 14858c2ecf20Sopenharmony_ci else 14868c2ecf20Sopenharmony_ci digital_tg_recv_dep_req(ddev, arg, resp); 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic int digital_tg_send_atr_res(struct nfc_digital_dev *ddev, 14908c2ecf20Sopenharmony_ci struct digital_atr_req *atr_req) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct digital_atr_res *atr_res; 14938c2ecf20Sopenharmony_ci struct sk_buff *skb; 14948c2ecf20Sopenharmony_ci u8 *gb, payload_bits; 14958c2ecf20Sopenharmony_ci size_t gb_len; 14968c2ecf20Sopenharmony_ci int rc; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci gb = nfc_get_local_general_bytes(ddev->nfc_dev, &gb_len); 14998c2ecf20Sopenharmony_ci if (!gb) 15008c2ecf20Sopenharmony_ci gb_len = 0; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci skb = digital_skb_alloc(ddev, sizeof(struct digital_atr_res) + gb_len); 15038c2ecf20Sopenharmony_ci if (!skb) 15048c2ecf20Sopenharmony_ci return -ENOMEM; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci skb_put(skb, sizeof(struct digital_atr_res)); 15078c2ecf20Sopenharmony_ci atr_res = (struct digital_atr_res *)skb->data; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci memset(atr_res, 0, sizeof(struct digital_atr_res)); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci atr_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; 15128c2ecf20Sopenharmony_ci atr_res->cmd = DIGITAL_CMD_ATR_RES; 15138c2ecf20Sopenharmony_ci memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3)); 15148c2ecf20Sopenharmony_ci atr_res->to = DIGITAL_NFC_DEP_TG_MAX_WT; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci ddev->local_payload_max = DIGITAL_PAYLOAD_SIZE_MAX; 15178c2ecf20Sopenharmony_ci payload_bits = digital_payload_size_to_bits(ddev->local_payload_max); 15188c2ecf20Sopenharmony_ci atr_res->pp = DIGITAL_PAYLOAD_BITS_TO_PP(payload_bits); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (gb_len) { 15218c2ecf20Sopenharmony_ci skb_put(skb, gb_len); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci atr_res->pp |= DIGITAL_GB_BIT; 15248c2ecf20Sopenharmony_ci memcpy(atr_res->gb, gb, gb_len); 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci digital_skb_push_dep_sod(ddev, skb); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci ddev->skb_add_crc(skb); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci ddev->curr_nfc_dep_pni = 0; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci rc = digital_tg_send_cmd(ddev, skb, 999, 15348c2ecf20Sopenharmony_ci digital_tg_send_atr_res_complete, NULL); 15358c2ecf20Sopenharmony_ci if (rc) 15368c2ecf20Sopenharmony_ci kfree_skb(skb); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci return rc; 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_civoid digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, 15428c2ecf20Sopenharmony_ci struct sk_buff *resp) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci int rc; 15458c2ecf20Sopenharmony_ci struct digital_atr_req *atr_req; 15468c2ecf20Sopenharmony_ci size_t gb_len, min_size; 15478c2ecf20Sopenharmony_ci u8 poll_tech_count, payload_bits; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (IS_ERR(resp)) { 15508c2ecf20Sopenharmony_ci rc = PTR_ERR(resp); 15518c2ecf20Sopenharmony_ci resp = NULL; 15528c2ecf20Sopenharmony_ci goto exit; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (!resp->len) { 15568c2ecf20Sopenharmony_ci rc = -EIO; 15578c2ecf20Sopenharmony_ci goto exit; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) { 15618c2ecf20Sopenharmony_ci min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2; 15628c2ecf20Sopenharmony_ci digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_106A); 15638c2ecf20Sopenharmony_ci } else { 15648c2ecf20Sopenharmony_ci min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1; 15658c2ecf20Sopenharmony_ci digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_212F); 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci if (resp->len < min_size) { 15698c2ecf20Sopenharmony_ci rc = -EIO; 15708c2ecf20Sopenharmony_ci goto exit; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci ddev->curr_protocol = NFC_PROTO_NFC_DEP_MASK; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci rc = ddev->skb_check_crc(resp); 15768c2ecf20Sopenharmony_ci if (rc) { 15778c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.6"); 15788c2ecf20Sopenharmony_ci goto exit; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci rc = digital_skb_pull_dep_sod(ddev, resp); 15828c2ecf20Sopenharmony_ci if (rc) { 15838c2ecf20Sopenharmony_ci PROTOCOL_ERR("14.4.1.2"); 15848c2ecf20Sopenharmony_ci goto exit; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci atr_req = (struct digital_atr_req *)resp->data; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (atr_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || 15908c2ecf20Sopenharmony_ci atr_req->cmd != DIGITAL_CMD_ATR_REQ || 15918c2ecf20Sopenharmony_ci atr_req->did > DIGITAL_DID_MAX) { 15928c2ecf20Sopenharmony_ci rc = -EINVAL; 15938c2ecf20Sopenharmony_ci goto exit; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci payload_bits = DIGITAL_PAYLOAD_PP_TO_BITS(atr_req->pp); 15978c2ecf20Sopenharmony_ci ddev->remote_payload_max = digital_payload_bits_to_size(payload_bits); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (!ddev->remote_payload_max) { 16008c2ecf20Sopenharmony_ci rc = -EINVAL; 16018c2ecf20Sopenharmony_ci goto exit; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci ddev->did = atr_req->did; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 16078c2ecf20Sopenharmony_ci NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED); 16088c2ecf20Sopenharmony_ci if (rc) 16098c2ecf20Sopenharmony_ci goto exit; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci rc = digital_tg_send_atr_res(ddev, atr_req); 16128c2ecf20Sopenharmony_ci if (rc) 16138c2ecf20Sopenharmony_ci goto exit; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci gb_len = resp->len - sizeof(struct digital_atr_req); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci poll_tech_count = ddev->poll_tech_count; 16188c2ecf20Sopenharmony_ci ddev->poll_tech_count = 0; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, 16218c2ecf20Sopenharmony_ci NFC_COMM_PASSIVE, atr_req->gb, gb_len); 16228c2ecf20Sopenharmony_ci if (rc) { 16238c2ecf20Sopenharmony_ci ddev->poll_tech_count = poll_tech_count; 16248c2ecf20Sopenharmony_ci goto exit; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci rc = 0; 16288c2ecf20Sopenharmony_ciexit: 16298c2ecf20Sopenharmony_ci if (rc) 16308c2ecf20Sopenharmony_ci digital_poll_next_tech(ddev); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci dev_kfree_skb(resp); 16338c2ecf20Sopenharmony_ci} 1634