18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * The NFC Controller Interface is the communication protocol between an 48c2ecf20Sopenharmony_ci * NFC Controller (NFCC) and a Device Host (DH). 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell International Ltd. 78c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Written by Ilan Elias <ilane@ti.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Acknowledgements: 128c2ecf20Sopenharmony_ci * This file is based on hci_event.c, which was written 138c2ecf20Sopenharmony_ci * by Maxim Krasnyansky. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/bitops.h> 218c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "../nfc.h" 248c2ecf20Sopenharmony_ci#include <net/nfc/nci.h> 258c2ecf20Sopenharmony_ci#include <net/nfc/nci_core.h> 268c2ecf20Sopenharmony_ci#include <linux/nfc.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Handle NCI Notification packets */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, 318c2ecf20Sopenharmony_ci struct sk_buff *skb) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct nci_core_conn_credit_ntf *ntf = (void *) skb->data; 348c2ecf20Sopenharmony_ci struct nci_conn_info *conn_info; 358c2ecf20Sopenharmony_ci int i; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci pr_debug("num_entries %d\n", ntf->num_entries); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (ntf->num_entries > NCI_MAX_NUM_CONN) 408c2ecf20Sopenharmony_ci ntf->num_entries = NCI_MAX_NUM_CONN; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* update the credits */ 438c2ecf20Sopenharmony_ci for (i = 0; i < ntf->num_entries; i++) { 448c2ecf20Sopenharmony_ci ntf->conn_entries[i].conn_id = 458c2ecf20Sopenharmony_ci nci_conn_id(&ntf->conn_entries[i].conn_id); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci pr_debug("entry[%d]: conn_id %d, credits %d\n", 488c2ecf20Sopenharmony_ci i, ntf->conn_entries[i].conn_id, 498c2ecf20Sopenharmony_ci ntf->conn_entries[i].credits); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci conn_info = nci_get_conn_info_by_conn_id(ndev, 528c2ecf20Sopenharmony_ci ntf->conn_entries[i].conn_id); 538c2ecf20Sopenharmony_ci if (!conn_info) 548c2ecf20Sopenharmony_ci return; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci atomic_add(ntf->conn_entries[i].credits, 578c2ecf20Sopenharmony_ci &conn_info->credits_cnt); 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* trigger the next tx */ 618c2ecf20Sopenharmony_ci if (!skb_queue_empty(&ndev->tx_q)) 628c2ecf20Sopenharmony_ci queue_work(ndev->tx_wq, &ndev->tx_work); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void nci_core_generic_error_ntf_packet(struct nci_dev *ndev, 668c2ecf20Sopenharmony_ci struct sk_buff *skb) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci __u8 status = skb->data[0]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci pr_debug("status 0x%x\n", status); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { 738c2ecf20Sopenharmony_ci /* Activation failed, so complete the request 748c2ecf20Sopenharmony_ci (the state remains the same) */ 758c2ecf20Sopenharmony_ci nci_req_complete(ndev, status); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, 808c2ecf20Sopenharmony_ci struct sk_buff *skb) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct nci_core_intf_error_ntf *ntf = (void *) skb->data; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ntf->conn_id = nci_conn_id(&ntf->conn_id); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci pr_debug("status 0x%x, conn_id %d\n", ntf->status, ntf->conn_id); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* complete the data exchange transaction, if exists */ 898c2ecf20Sopenharmony_ci if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) 908c2ecf20Sopenharmony_ci nci_data_exchange_complete(ndev, NULL, ntf->conn_id, -EIO); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, 948c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfca_poll *nfca_poll, 958c2ecf20Sopenharmony_ci __u8 *data) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci nfca_poll->sens_res = __le16_to_cpu(*((__le16 *)data)); 988c2ecf20Sopenharmony_ci data += 2; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci pr_debug("sens_res 0x%x, nfcid1_len %d\n", 1038c2ecf20Sopenharmony_ci nfca_poll->sens_res, nfca_poll->nfcid1_len); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len); 1068c2ecf20Sopenharmony_ci data += nfca_poll->nfcid1_len; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci nfca_poll->sel_res_len = *data++; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (nfca_poll->sel_res_len != 0) 1118c2ecf20Sopenharmony_ci nfca_poll->sel_res = *data++; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci pr_debug("sel_res_len %d, sel_res 0x%x\n", 1148c2ecf20Sopenharmony_ci nfca_poll->sel_res_len, 1158c2ecf20Sopenharmony_ci nfca_poll->sel_res); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return data; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, 1218c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcb_poll *nfcb_poll, 1228c2ecf20Sopenharmony_ci __u8 *data) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len); 1298c2ecf20Sopenharmony_ci data += nfcb_poll->sensb_res_len; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return data; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, 1358c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcf_poll *nfcf_poll, 1368c2ecf20Sopenharmony_ci __u8 *data) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci nfcf_poll->bit_rate = *data++; 1398c2ecf20Sopenharmony_ci nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci pr_debug("bit_rate %d, sensf_res_len %d\n", 1428c2ecf20Sopenharmony_ci nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len); 1458c2ecf20Sopenharmony_ci data += nfcf_poll->sensf_res_len; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return data; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic __u8 *nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev, 1518c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcv_poll *nfcv_poll, 1528c2ecf20Sopenharmony_ci __u8 *data) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci ++data; 1558c2ecf20Sopenharmony_ci nfcv_poll->dsfid = *data++; 1568c2ecf20Sopenharmony_ci memcpy(nfcv_poll->uid, data, NFC_ISO15693_UID_MAXSIZE); 1578c2ecf20Sopenharmony_ci data += NFC_ISO15693_UID_MAXSIZE; 1588c2ecf20Sopenharmony_ci return data; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic __u8 *nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev, 1628c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcf_listen *nfcf_listen, 1638c2ecf20Sopenharmony_ci __u8 *data) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci nfcf_listen->local_nfcid2_len = min_t(__u8, *data++, 1668c2ecf20Sopenharmony_ci NFC_NFCID2_MAXSIZE); 1678c2ecf20Sopenharmony_ci memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len); 1688c2ecf20Sopenharmony_ci data += nfcf_listen->local_nfcid2_len; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return data; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic __u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci if (ndev->ops->get_rfprotocol) 1768c2ecf20Sopenharmony_ci return ndev->ops->get_rfprotocol(ndev, rf_protocol); 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int nci_add_new_protocol(struct nci_dev *ndev, 1818c2ecf20Sopenharmony_ci struct nfc_target *target, 1828c2ecf20Sopenharmony_ci __u8 rf_protocol, 1838c2ecf20Sopenharmony_ci __u8 rf_tech_and_mode, 1848c2ecf20Sopenharmony_ci void *params) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfca_poll *nfca_poll; 1878c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcb_poll *nfcb_poll; 1888c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcf_poll *nfcf_poll; 1898c2ecf20Sopenharmony_ci struct rf_tech_specific_params_nfcv_poll *nfcv_poll; 1908c2ecf20Sopenharmony_ci __u32 protocol; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (rf_protocol == NCI_RF_PROTOCOL_T1T) 1938c2ecf20Sopenharmony_ci protocol = NFC_PROTO_JEWEL_MASK; 1948c2ecf20Sopenharmony_ci else if (rf_protocol == NCI_RF_PROTOCOL_T2T) 1958c2ecf20Sopenharmony_ci protocol = NFC_PROTO_MIFARE_MASK; 1968c2ecf20Sopenharmony_ci else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) 1978c2ecf20Sopenharmony_ci if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) 1988c2ecf20Sopenharmony_ci protocol = NFC_PROTO_ISO14443_MASK; 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci protocol = NFC_PROTO_ISO14443_B_MASK; 2018c2ecf20Sopenharmony_ci else if (rf_protocol == NCI_RF_PROTOCOL_T3T) 2028c2ecf20Sopenharmony_ci protocol = NFC_PROTO_FELICA_MASK; 2038c2ecf20Sopenharmony_ci else if (rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) 2048c2ecf20Sopenharmony_ci protocol = NFC_PROTO_NFC_DEP_MASK; 2058c2ecf20Sopenharmony_ci else if (rf_protocol == NCI_RF_PROTOCOL_T5T) 2068c2ecf20Sopenharmony_ci protocol = NFC_PROTO_ISO15693_MASK; 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci protocol = nci_get_prop_rf_protocol(ndev, rf_protocol); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!(protocol & ndev->poll_prots)) { 2118c2ecf20Sopenharmony_ci pr_err("the target found does not have the desired protocol\n"); 2128c2ecf20Sopenharmony_ci return -EPROTO; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { 2168c2ecf20Sopenharmony_ci nfca_poll = (struct rf_tech_specific_params_nfca_poll *)params; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci target->sens_res = nfca_poll->sens_res; 2198c2ecf20Sopenharmony_ci target->sel_res = nfca_poll->sel_res; 2208c2ecf20Sopenharmony_ci target->nfcid1_len = nfca_poll->nfcid1_len; 2218c2ecf20Sopenharmony_ci if (target->nfcid1_len > ARRAY_SIZE(target->nfcid1)) 2228c2ecf20Sopenharmony_ci return -EPROTO; 2238c2ecf20Sopenharmony_ci if (target->nfcid1_len > 0) { 2248c2ecf20Sopenharmony_ci memcpy(target->nfcid1, nfca_poll->nfcid1, 2258c2ecf20Sopenharmony_ci target->nfcid1_len); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci } else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) { 2288c2ecf20Sopenharmony_ci nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci target->sensb_res_len = nfcb_poll->sensb_res_len; 2318c2ecf20Sopenharmony_ci if (target->sensb_res_len > ARRAY_SIZE(target->sensb_res)) 2328c2ecf20Sopenharmony_ci return -EPROTO; 2338c2ecf20Sopenharmony_ci if (target->sensb_res_len > 0) { 2348c2ecf20Sopenharmony_ci memcpy(target->sensb_res, nfcb_poll->sensb_res, 2358c2ecf20Sopenharmony_ci target->sensb_res_len); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci } else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) { 2388c2ecf20Sopenharmony_ci nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci target->sensf_res_len = nfcf_poll->sensf_res_len; 2418c2ecf20Sopenharmony_ci if (target->sensf_res_len > ARRAY_SIZE(target->sensf_res)) 2428c2ecf20Sopenharmony_ci return -EPROTO; 2438c2ecf20Sopenharmony_ci if (target->sensf_res_len > 0) { 2448c2ecf20Sopenharmony_ci memcpy(target->sensf_res, nfcf_poll->sensf_res, 2458c2ecf20Sopenharmony_ci target->sensf_res_len); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci } else if (rf_tech_and_mode == NCI_NFC_V_PASSIVE_POLL_MODE) { 2488c2ecf20Sopenharmony_ci nfcv_poll = (struct rf_tech_specific_params_nfcv_poll *)params; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci target->is_iso15693 = 1; 2518c2ecf20Sopenharmony_ci target->iso15693_dsfid = nfcv_poll->dsfid; 2528c2ecf20Sopenharmony_ci memcpy(target->iso15693_uid, nfcv_poll->uid, NFC_ISO15693_UID_MAXSIZE); 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode); 2558c2ecf20Sopenharmony_ci return -EPROTO; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci target->supported_protocols |= protocol; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci pr_debug("protocol 0x%x\n", protocol); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void nci_add_new_target(struct nci_dev *ndev, 2668c2ecf20Sopenharmony_ci struct nci_rf_discover_ntf *ntf) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct nfc_target *target; 2698c2ecf20Sopenharmony_ci int i, rc; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci for (i = 0; i < ndev->n_targets; i++) { 2728c2ecf20Sopenharmony_ci target = &ndev->targets[i]; 2738c2ecf20Sopenharmony_ci if (target->logical_idx == ntf->rf_discovery_id) { 2748c2ecf20Sopenharmony_ci /* This target already exists, add the new protocol */ 2758c2ecf20Sopenharmony_ci nci_add_new_protocol(ndev, target, ntf->rf_protocol, 2768c2ecf20Sopenharmony_ci ntf->rf_tech_and_mode, 2778c2ecf20Sopenharmony_ci &ntf->rf_tech_specific_params); 2788c2ecf20Sopenharmony_ci return; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* This is a new target, check if we've enough room */ 2838c2ecf20Sopenharmony_ci if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) { 2848c2ecf20Sopenharmony_ci pr_debug("not enough room, ignoring new target...\n"); 2858c2ecf20Sopenharmony_ci return; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci target = &ndev->targets[ndev->n_targets]; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, 2918c2ecf20Sopenharmony_ci ntf->rf_tech_and_mode, 2928c2ecf20Sopenharmony_ci &ntf->rf_tech_specific_params); 2938c2ecf20Sopenharmony_ci if (!rc) { 2948c2ecf20Sopenharmony_ci target->logical_idx = ntf->rf_discovery_id; 2958c2ecf20Sopenharmony_ci ndev->n_targets++; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci pr_debug("logical idx %d, n_targets %d\n", target->logical_idx, 2988c2ecf20Sopenharmony_ci ndev->n_targets); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_civoid nci_clear_target_list(struct nci_dev *ndev) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci memset(ndev->targets, 0, 3058c2ecf20Sopenharmony_ci (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS)); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ndev->n_targets = 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic void nci_rf_discover_ntf_packet(struct nci_dev *ndev, 3118c2ecf20Sopenharmony_ci struct sk_buff *skb) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct nci_rf_discover_ntf ntf; 3148c2ecf20Sopenharmony_ci __u8 *data = skb->data; 3158c2ecf20Sopenharmony_ci bool add_target = true; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ntf.rf_discovery_id = *data++; 3188c2ecf20Sopenharmony_ci ntf.rf_protocol = *data++; 3198c2ecf20Sopenharmony_ci ntf.rf_tech_and_mode = *data++; 3208c2ecf20Sopenharmony_ci ntf.rf_tech_specific_params_len = *data++; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id); 3238c2ecf20Sopenharmony_ci pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol); 3248c2ecf20Sopenharmony_ci pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode); 3258c2ecf20Sopenharmony_ci pr_debug("rf_tech_specific_params_len %d\n", 3268c2ecf20Sopenharmony_ci ntf.rf_tech_specific_params_len); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (ntf.rf_tech_specific_params_len > 0) { 3298c2ecf20Sopenharmony_ci switch (ntf.rf_tech_and_mode) { 3308c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_POLL_MODE: 3318c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfca_passive_poll(ndev, 3328c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfca_poll), data); 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci case NCI_NFC_B_PASSIVE_POLL_MODE: 3368c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcb_passive_poll(ndev, 3378c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcb_poll), data); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_POLL_MODE: 3418c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcf_passive_poll(ndev, 3428c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcf_poll), data); 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci case NCI_NFC_V_PASSIVE_POLL_MODE: 3468c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcv_passive_poll(ndev, 3478c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcv_poll), data); 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci default: 3518c2ecf20Sopenharmony_ci pr_err("unsupported rf_tech_and_mode 0x%x\n", 3528c2ecf20Sopenharmony_ci ntf.rf_tech_and_mode); 3538c2ecf20Sopenharmony_ci data += ntf.rf_tech_specific_params_len; 3548c2ecf20Sopenharmony_ci add_target = false; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ntf.ntf_type = *data++; 3598c2ecf20Sopenharmony_ci pr_debug("ntf_type %d\n", ntf.ntf_type); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (add_target == true) 3628c2ecf20Sopenharmony_ci nci_add_new_target(ndev, &ntf); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (ntf.ntf_type == NCI_DISCOVER_NTF_TYPE_MORE) { 3658c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_W4_ALL_DISCOVERIES); 3668c2ecf20Sopenharmony_ci } else { 3678c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_W4_HOST_SELECT); 3688c2ecf20Sopenharmony_ci nfc_targets_found(ndev->nfc_dev, ndev->targets, 3698c2ecf20Sopenharmony_ci ndev->n_targets); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, 3748c2ecf20Sopenharmony_ci struct nci_rf_intf_activated_ntf *ntf, __u8 *data) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct activation_params_nfca_poll_iso_dep *nfca_poll; 3778c2ecf20Sopenharmony_ci struct activation_params_nfcb_poll_iso_dep *nfcb_poll; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci switch (ntf->activation_rf_tech_and_mode) { 3808c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_POLL_MODE: 3818c2ecf20Sopenharmony_ci nfca_poll = &ntf->activation_params.nfca_poll_iso_dep; 3828c2ecf20Sopenharmony_ci nfca_poll->rats_res_len = min_t(__u8, *data++, 20); 3838c2ecf20Sopenharmony_ci pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len); 3848c2ecf20Sopenharmony_ci if (nfca_poll->rats_res_len > 0) { 3858c2ecf20Sopenharmony_ci memcpy(nfca_poll->rats_res, 3868c2ecf20Sopenharmony_ci data, nfca_poll->rats_res_len); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci case NCI_NFC_B_PASSIVE_POLL_MODE: 3918c2ecf20Sopenharmony_ci nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep; 3928c2ecf20Sopenharmony_ci nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50); 3938c2ecf20Sopenharmony_ci pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len); 3948c2ecf20Sopenharmony_ci if (nfcb_poll->attrib_res_len > 0) { 3958c2ecf20Sopenharmony_ci memcpy(nfcb_poll->attrib_res, 3968c2ecf20Sopenharmony_ci data, nfcb_poll->attrib_res_len); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci default: 4018c2ecf20Sopenharmony_ci pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", 4028c2ecf20Sopenharmony_ci ntf->activation_rf_tech_and_mode); 4038c2ecf20Sopenharmony_ci return NCI_STATUS_RF_PROTOCOL_ERROR; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return NCI_STATUS_OK; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, 4108c2ecf20Sopenharmony_ci struct nci_rf_intf_activated_ntf *ntf, __u8 *data) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct activation_params_poll_nfc_dep *poll; 4138c2ecf20Sopenharmony_ci struct activation_params_listen_nfc_dep *listen; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci switch (ntf->activation_rf_tech_and_mode) { 4168c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_POLL_MODE: 4178c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_POLL_MODE: 4188c2ecf20Sopenharmony_ci poll = &ntf->activation_params.poll_nfc_dep; 4198c2ecf20Sopenharmony_ci poll->atr_res_len = min_t(__u8, *data++, 4208c2ecf20Sopenharmony_ci NFC_ATR_RES_MAXSIZE - 2); 4218c2ecf20Sopenharmony_ci pr_debug("atr_res_len %d\n", poll->atr_res_len); 4228c2ecf20Sopenharmony_ci if (poll->atr_res_len > 0) 4238c2ecf20Sopenharmony_ci memcpy(poll->atr_res, data, poll->atr_res_len); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_LISTEN_MODE: 4278c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_LISTEN_MODE: 4288c2ecf20Sopenharmony_ci listen = &ntf->activation_params.listen_nfc_dep; 4298c2ecf20Sopenharmony_ci listen->atr_req_len = min_t(__u8, *data++, 4308c2ecf20Sopenharmony_ci NFC_ATR_REQ_MAXSIZE - 2); 4318c2ecf20Sopenharmony_ci pr_debug("atr_req_len %d\n", listen->atr_req_len); 4328c2ecf20Sopenharmony_ci if (listen->atr_req_len > 0) 4338c2ecf20Sopenharmony_ci memcpy(listen->atr_req, data, listen->atr_req_len); 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci default: 4378c2ecf20Sopenharmony_ci pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", 4388c2ecf20Sopenharmony_ci ntf->activation_rf_tech_and_mode); 4398c2ecf20Sopenharmony_ci return NCI_STATUS_RF_PROTOCOL_ERROR; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return NCI_STATUS_OK; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void nci_target_auto_activated(struct nci_dev *ndev, 4468c2ecf20Sopenharmony_ci struct nci_rf_intf_activated_ntf *ntf) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct nfc_target *target; 4498c2ecf20Sopenharmony_ci int rc; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci target = &ndev->targets[ndev->n_targets]; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, 4548c2ecf20Sopenharmony_ci ntf->activation_rf_tech_and_mode, 4558c2ecf20Sopenharmony_ci &ntf->rf_tech_specific_params); 4568c2ecf20Sopenharmony_ci if (rc) 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci target->logical_idx = ntf->rf_discovery_id; 4608c2ecf20Sopenharmony_ci ndev->n_targets++; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci pr_debug("logical idx %d, n_targets %d\n", 4638c2ecf20Sopenharmony_ci target->logical_idx, ndev->n_targets); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int nci_store_general_bytes_nfc_dep(struct nci_dev *ndev, 4698c2ecf20Sopenharmony_ci struct nci_rf_intf_activated_ntf *ntf) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci ndev->remote_gb_len = 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (ntf->activation_params_len <= 0) 4748c2ecf20Sopenharmony_ci return NCI_STATUS_OK; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci switch (ntf->activation_rf_tech_and_mode) { 4778c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_POLL_MODE: 4788c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_POLL_MODE: 4798c2ecf20Sopenharmony_ci ndev->remote_gb_len = min_t(__u8, 4808c2ecf20Sopenharmony_ci (ntf->activation_params.poll_nfc_dep.atr_res_len 4818c2ecf20Sopenharmony_ci - NFC_ATR_RES_GT_OFFSET), 4828c2ecf20Sopenharmony_ci NFC_ATR_RES_GB_MAXSIZE); 4838c2ecf20Sopenharmony_ci memcpy(ndev->remote_gb, 4848c2ecf20Sopenharmony_ci (ntf->activation_params.poll_nfc_dep.atr_res 4858c2ecf20Sopenharmony_ci + NFC_ATR_RES_GT_OFFSET), 4868c2ecf20Sopenharmony_ci ndev->remote_gb_len); 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_LISTEN_MODE: 4908c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_LISTEN_MODE: 4918c2ecf20Sopenharmony_ci ndev->remote_gb_len = min_t(__u8, 4928c2ecf20Sopenharmony_ci (ntf->activation_params.listen_nfc_dep.atr_req_len 4938c2ecf20Sopenharmony_ci - NFC_ATR_REQ_GT_OFFSET), 4948c2ecf20Sopenharmony_ci NFC_ATR_REQ_GB_MAXSIZE); 4958c2ecf20Sopenharmony_ci memcpy(ndev->remote_gb, 4968c2ecf20Sopenharmony_ci (ntf->activation_params.listen_nfc_dep.atr_req 4978c2ecf20Sopenharmony_ci + NFC_ATR_REQ_GT_OFFSET), 4988c2ecf20Sopenharmony_ci ndev->remote_gb_len); 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci default: 5028c2ecf20Sopenharmony_ci pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", 5038c2ecf20Sopenharmony_ci ntf->activation_rf_tech_and_mode); 5048c2ecf20Sopenharmony_ci return NCI_STATUS_RF_PROTOCOL_ERROR; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return NCI_STATUS_OK; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, 5118c2ecf20Sopenharmony_ci struct sk_buff *skb) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct nci_conn_info *conn_info; 5148c2ecf20Sopenharmony_ci struct nci_rf_intf_activated_ntf ntf; 5158c2ecf20Sopenharmony_ci __u8 *data = skb->data; 5168c2ecf20Sopenharmony_ci int err = NCI_STATUS_OK; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ntf.rf_discovery_id = *data++; 5198c2ecf20Sopenharmony_ci ntf.rf_interface = *data++; 5208c2ecf20Sopenharmony_ci ntf.rf_protocol = *data++; 5218c2ecf20Sopenharmony_ci ntf.activation_rf_tech_and_mode = *data++; 5228c2ecf20Sopenharmony_ci ntf.max_data_pkt_payload_size = *data++; 5238c2ecf20Sopenharmony_ci ntf.initial_num_credits = *data++; 5248c2ecf20Sopenharmony_ci ntf.rf_tech_specific_params_len = *data++; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id); 5278c2ecf20Sopenharmony_ci pr_debug("rf_interface 0x%x\n", ntf.rf_interface); 5288c2ecf20Sopenharmony_ci pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol); 5298c2ecf20Sopenharmony_ci pr_debug("activation_rf_tech_and_mode 0x%x\n", 5308c2ecf20Sopenharmony_ci ntf.activation_rf_tech_and_mode); 5318c2ecf20Sopenharmony_ci pr_debug("max_data_pkt_payload_size 0x%x\n", 5328c2ecf20Sopenharmony_ci ntf.max_data_pkt_payload_size); 5338c2ecf20Sopenharmony_ci pr_debug("initial_num_credits 0x%x\n", 5348c2ecf20Sopenharmony_ci ntf.initial_num_credits); 5358c2ecf20Sopenharmony_ci pr_debug("rf_tech_specific_params_len %d\n", 5368c2ecf20Sopenharmony_ci ntf.rf_tech_specific_params_len); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* If this contains a value of 0x00 (NFCEE Direct RF 5398c2ecf20Sopenharmony_ci * Interface) then all following parameters SHALL contain a 5408c2ecf20Sopenharmony_ci * value of 0 and SHALL be ignored. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci if (ntf.rf_interface == NCI_RF_INTERFACE_NFCEE_DIRECT) 5438c2ecf20Sopenharmony_ci goto listen; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (ntf.rf_tech_specific_params_len > 0) { 5468c2ecf20Sopenharmony_ci switch (ntf.activation_rf_tech_and_mode) { 5478c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_POLL_MODE: 5488c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfca_passive_poll(ndev, 5498c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfca_poll), data); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci case NCI_NFC_B_PASSIVE_POLL_MODE: 5538c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcb_passive_poll(ndev, 5548c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcb_poll), data); 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_POLL_MODE: 5588c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcf_passive_poll(ndev, 5598c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcf_poll), data); 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci case NCI_NFC_V_PASSIVE_POLL_MODE: 5638c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcv_passive_poll(ndev, 5648c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcv_poll), data); 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci case NCI_NFC_A_PASSIVE_LISTEN_MODE: 5688c2ecf20Sopenharmony_ci /* no RF technology specific parameters */ 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci case NCI_NFC_F_PASSIVE_LISTEN_MODE: 5728c2ecf20Sopenharmony_ci data = nci_extract_rf_params_nfcf_passive_listen(ndev, 5738c2ecf20Sopenharmony_ci &(ntf.rf_tech_specific_params.nfcf_listen), 5748c2ecf20Sopenharmony_ci data); 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci default: 5788c2ecf20Sopenharmony_ci pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", 5798c2ecf20Sopenharmony_ci ntf.activation_rf_tech_and_mode); 5808c2ecf20Sopenharmony_ci err = NCI_STATUS_RF_PROTOCOL_ERROR; 5818c2ecf20Sopenharmony_ci goto exit; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci ntf.data_exch_rf_tech_and_mode = *data++; 5868c2ecf20Sopenharmony_ci ntf.data_exch_tx_bit_rate = *data++; 5878c2ecf20Sopenharmony_ci ntf.data_exch_rx_bit_rate = *data++; 5888c2ecf20Sopenharmony_ci ntf.activation_params_len = *data++; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci pr_debug("data_exch_rf_tech_and_mode 0x%x\n", 5918c2ecf20Sopenharmony_ci ntf.data_exch_rf_tech_and_mode); 5928c2ecf20Sopenharmony_ci pr_debug("data_exch_tx_bit_rate 0x%x\n", ntf.data_exch_tx_bit_rate); 5938c2ecf20Sopenharmony_ci pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate); 5948c2ecf20Sopenharmony_ci pr_debug("activation_params_len %d\n", ntf.activation_params_len); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (ntf.activation_params_len > 0) { 5978c2ecf20Sopenharmony_ci switch (ntf.rf_interface) { 5988c2ecf20Sopenharmony_ci case NCI_RF_INTERFACE_ISO_DEP: 5998c2ecf20Sopenharmony_ci err = nci_extract_activation_params_iso_dep(ndev, 6008c2ecf20Sopenharmony_ci &ntf, data); 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci case NCI_RF_INTERFACE_NFC_DEP: 6048c2ecf20Sopenharmony_ci err = nci_extract_activation_params_nfc_dep(ndev, 6058c2ecf20Sopenharmony_ci &ntf, data); 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci case NCI_RF_INTERFACE_FRAME: 6098c2ecf20Sopenharmony_ci /* no activation params */ 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci default: 6138c2ecf20Sopenharmony_ci pr_err("unsupported rf_interface 0x%x\n", 6148c2ecf20Sopenharmony_ci ntf.rf_interface); 6158c2ecf20Sopenharmony_ci err = NCI_STATUS_RF_PROTOCOL_ERROR; 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ciexit: 6218c2ecf20Sopenharmony_ci if (err == NCI_STATUS_OK) { 6228c2ecf20Sopenharmony_ci conn_info = ndev->rf_conn_info; 6238c2ecf20Sopenharmony_ci if (!conn_info) 6248c2ecf20Sopenharmony_ci return; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci conn_info->max_pkt_payload_len = ntf.max_data_pkt_payload_size; 6278c2ecf20Sopenharmony_ci conn_info->initial_num_credits = ntf.initial_num_credits; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* set the available credits to initial value */ 6308c2ecf20Sopenharmony_ci atomic_set(&conn_info->credits_cnt, 6318c2ecf20Sopenharmony_ci conn_info->initial_num_credits); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* store general bytes to be reported later in dep_link_up */ 6348c2ecf20Sopenharmony_ci if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) { 6358c2ecf20Sopenharmony_ci err = nci_store_general_bytes_nfc_dep(ndev, &ntf); 6368c2ecf20Sopenharmony_ci if (err != NCI_STATUS_OK) 6378c2ecf20Sopenharmony_ci pr_err("unable to store general bytes\n"); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!(ntf.activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK)) { 6428c2ecf20Sopenharmony_ci /* Poll mode */ 6438c2ecf20Sopenharmony_ci if (atomic_read(&ndev->state) == NCI_DISCOVERY) { 6448c2ecf20Sopenharmony_ci /* A single target was found and activated 6458c2ecf20Sopenharmony_ci * automatically */ 6468c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_POLL_ACTIVE); 6478c2ecf20Sopenharmony_ci if (err == NCI_STATUS_OK) 6488c2ecf20Sopenharmony_ci nci_target_auto_activated(ndev, &ntf); 6498c2ecf20Sopenharmony_ci } else { /* ndev->state == NCI_W4_HOST_SELECT */ 6508c2ecf20Sopenharmony_ci /* A selected target was activated, so complete the 6518c2ecf20Sopenharmony_ci * request */ 6528c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_POLL_ACTIVE); 6538c2ecf20Sopenharmony_ci nci_req_complete(ndev, err); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci } else { 6568c2ecf20Sopenharmony_cilisten: 6578c2ecf20Sopenharmony_ci /* Listen mode */ 6588c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_LISTEN_ACTIVE); 6598c2ecf20Sopenharmony_ci if (err == NCI_STATUS_OK && 6608c2ecf20Sopenharmony_ci ntf.rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) { 6618c2ecf20Sopenharmony_ci err = nfc_tm_activated(ndev->nfc_dev, 6628c2ecf20Sopenharmony_ci NFC_PROTO_NFC_DEP_MASK, 6638c2ecf20Sopenharmony_ci NFC_COMM_PASSIVE, 6648c2ecf20Sopenharmony_ci ndev->remote_gb, 6658c2ecf20Sopenharmony_ci ndev->remote_gb_len); 6668c2ecf20Sopenharmony_ci if (err != NCI_STATUS_OK) 6678c2ecf20Sopenharmony_ci pr_err("error when signaling tm activation\n"); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, 6738c2ecf20Sopenharmony_ci struct sk_buff *skb) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct nci_conn_info *conn_info; 6768c2ecf20Sopenharmony_ci struct nci_rf_deactivate_ntf *ntf = (void *) skb->data; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci conn_info = ndev->rf_conn_info; 6818c2ecf20Sopenharmony_ci if (!conn_info) 6828c2ecf20Sopenharmony_ci return; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* drop tx data queue */ 6858c2ecf20Sopenharmony_ci skb_queue_purge(&ndev->tx_q); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* drop partial rx data packet */ 6888c2ecf20Sopenharmony_ci if (ndev->rx_data_reassembly) { 6898c2ecf20Sopenharmony_ci kfree_skb(ndev->rx_data_reassembly); 6908c2ecf20Sopenharmony_ci ndev->rx_data_reassembly = NULL; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* complete the data exchange transaction, if exists */ 6948c2ecf20Sopenharmony_ci if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) 6958c2ecf20Sopenharmony_ci nci_data_exchange_complete(ndev, NULL, NCI_STATIC_RF_CONN_ID, 6968c2ecf20Sopenharmony_ci -EIO); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci switch (ntf->type) { 6998c2ecf20Sopenharmony_ci case NCI_DEACTIVATE_TYPE_IDLE_MODE: 7008c2ecf20Sopenharmony_ci nci_clear_target_list(ndev); 7018c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_IDLE); 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci case NCI_DEACTIVATE_TYPE_SLEEP_MODE: 7048c2ecf20Sopenharmony_ci case NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE: 7058c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_W4_HOST_SELECT); 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case NCI_DEACTIVATE_TYPE_DISCOVERY: 7088c2ecf20Sopenharmony_ci nci_clear_target_list(ndev); 7098c2ecf20Sopenharmony_ci atomic_set(&ndev->state, NCI_DISCOVERY); 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci nci_req_complete(ndev, NCI_STATUS_OK); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic void nci_nfcee_discover_ntf_packet(struct nci_dev *ndev, 7178c2ecf20Sopenharmony_ci struct sk_buff *skb) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci u8 status = NCI_STATUS_OK; 7208c2ecf20Sopenharmony_ci struct nci_nfcee_discover_ntf *nfcee_ntf = 7218c2ecf20Sopenharmony_ci (struct nci_nfcee_discover_ntf *)skb->data; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci pr_debug("\n"); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* NFCForum NCI 9.2.1 HCI Network Specific Handling 7268c2ecf20Sopenharmony_ci * If the NFCC supports the HCI Network, it SHALL return one, 7278c2ecf20Sopenharmony_ci * and only one, NFCEE_DISCOVER_NTF with a Protocol type of 7288c2ecf20Sopenharmony_ci * “HCI Access”, even if the HCI Network contains multiple NFCEEs. 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_ci ndev->hci_dev->nfcee_id = nfcee_ntf->nfcee_id; 7318c2ecf20Sopenharmony_ci ndev->cur_params.id = nfcee_ntf->nfcee_id; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci nci_req_complete(ndev, status); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic void nci_nfcee_action_ntf_packet(struct nci_dev *ndev, 7378c2ecf20Sopenharmony_ci struct sk_buff *skb) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci pr_debug("\n"); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_civoid nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci __u16 ntf_opcode = nci_opcode(skb->data); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci pr_debug("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n", 7478c2ecf20Sopenharmony_ci nci_pbf(skb->data), 7488c2ecf20Sopenharmony_ci nci_opcode_gid(ntf_opcode), 7498c2ecf20Sopenharmony_ci nci_opcode_oid(ntf_opcode), 7508c2ecf20Sopenharmony_ci nci_plen(skb->data)); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* strip the nci control header */ 7538c2ecf20Sopenharmony_ci skb_pull(skb, NCI_CTRL_HDR_SIZE); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (nci_opcode_gid(ntf_opcode) == NCI_GID_PROPRIETARY) { 7568c2ecf20Sopenharmony_ci if (nci_prop_ntf_packet(ndev, ntf_opcode, skb) == -ENOTSUPP) { 7578c2ecf20Sopenharmony_ci pr_err("unsupported ntf opcode 0x%x\n", 7588c2ecf20Sopenharmony_ci ntf_opcode); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci goto end; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci switch (ntf_opcode) { 7658c2ecf20Sopenharmony_ci case NCI_OP_CORE_CONN_CREDITS_NTF: 7668c2ecf20Sopenharmony_ci nci_core_conn_credits_ntf_packet(ndev, skb); 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci case NCI_OP_CORE_GENERIC_ERROR_NTF: 7708c2ecf20Sopenharmony_ci nci_core_generic_error_ntf_packet(ndev, skb); 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci case NCI_OP_CORE_INTF_ERROR_NTF: 7748c2ecf20Sopenharmony_ci nci_core_conn_intf_error_ntf_packet(ndev, skb); 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci case NCI_OP_RF_DISCOVER_NTF: 7788c2ecf20Sopenharmony_ci nci_rf_discover_ntf_packet(ndev, skb); 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci case NCI_OP_RF_INTF_ACTIVATED_NTF: 7828c2ecf20Sopenharmony_ci nci_rf_intf_activated_ntf_packet(ndev, skb); 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci case NCI_OP_RF_DEACTIVATE_NTF: 7868c2ecf20Sopenharmony_ci nci_rf_deactivate_ntf_packet(ndev, skb); 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci case NCI_OP_NFCEE_DISCOVER_NTF: 7908c2ecf20Sopenharmony_ci nci_nfcee_discover_ntf_packet(ndev, skb); 7918c2ecf20Sopenharmony_ci break; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci case NCI_OP_RF_NFCEE_ACTION_NTF: 7948c2ecf20Sopenharmony_ci nci_nfcee_action_ntf_packet(ndev, skb); 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci default: 7988c2ecf20Sopenharmony_ci pr_err("unknown ntf opcode 0x%x\n", ntf_opcode); 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci nci_core_ntf_packet(ndev, ntf_opcode, skb); 8038c2ecf20Sopenharmony_ciend: 8048c2ecf20Sopenharmony_ci kfree_skb(skb); 8058c2ecf20Sopenharmony_ci} 806