18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * HCI based Driver for NXP PN544 NFC Chip 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/nfc.h> 158c2ecf20Sopenharmony_ci#include <net/nfc/hci.h> 168c2ecf20Sopenharmony_ci#include <net/nfc/llc.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "pn544.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* Timing restrictions (ms) */ 218c2ecf20Sopenharmony_ci#define PN544_HCI_RESETVEN_TIME 30 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum pn544_state { 248c2ecf20Sopenharmony_ci PN544_ST_COLD, 258c2ecf20Sopenharmony_ci PN544_ST_FW_READY, 268c2ecf20Sopenharmony_ci PN544_ST_READY, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define FULL_VERSION_LEN 11 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Proprietary commands */ 328c2ecf20Sopenharmony_ci#define PN544_WRITE 0x3f 338c2ecf20Sopenharmony_ci#define PN544_TEST_SWP 0x21 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Proprietary gates, events, commands and registers */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* NFC_HCI_RF_READER_A_GATE additional registers and commands */ 388c2ecf20Sopenharmony_ci#define PN544_RF_READER_A_AUTO_ACTIVATION 0x10 398c2ecf20Sopenharmony_ci#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12 408c2ecf20Sopenharmony_ci#define PN544_MIFARE_CMD 0x21 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Commands that apply to all RF readers */ 438c2ecf20Sopenharmony_ci#define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30 448c2ecf20Sopenharmony_ci#define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* NFC_HCI_ID_MGMT_GATE additional registers */ 478c2ecf20Sopenharmony_ci#define PN544_ID_MGMT_FULL_VERSION_SW 0x10 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define PN544_RF_READER_ISO15693_GATE 0x12 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define PN544_RF_READER_F_GATE 0x14 528c2ecf20Sopenharmony_ci#define PN544_FELICA_ID 0x04 538c2ecf20Sopenharmony_ci#define PN544_FELICA_RAW 0x20 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define PN544_RF_READER_JEWEL_GATE 0x15 568c2ecf20Sopenharmony_ci#define PN544_JEWEL_RAW_CMD 0x23 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30 598c2ecf20Sopenharmony_ci#define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define PN544_SYS_MGMT_GATE 0x90 628c2ecf20Sopenharmony_ci#define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define PN544_POLLING_LOOP_MGMT_GATE 0x94 658c2ecf20Sopenharmony_ci#define PN544_DEP_MODE 0x01 668c2ecf20Sopenharmony_ci#define PN544_DEP_ATR_REQ 0x02 678c2ecf20Sopenharmony_ci#define PN544_DEP_ATR_RES 0x03 688c2ecf20Sopenharmony_ci#define PN544_DEP_MERGE 0x0D 698c2ecf20Sopenharmony_ci#define PN544_PL_RDPHASES 0x06 708c2ecf20Sopenharmony_ci#define PN544_PL_EMULATION 0x07 718c2ecf20Sopenharmony_ci#define PN544_PL_NFCT_DEACTIVATED 0x09 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define PN544_SWP_MGMT_GATE 0xA0 748c2ecf20Sopenharmony_ci#define PN544_SWP_DEFAULT_MODE 0x01 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define PN544_NFC_WI_MGMT_GATE 0xA1 778c2ecf20Sopenharmony_ci#define PN544_NFC_ESE_DEFAULT_MODE 0x01 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define PN544_HCI_EVT_SND_DATA 0x01 808c2ecf20Sopenharmony_ci#define PN544_HCI_EVT_ACTIVATED 0x02 818c2ecf20Sopenharmony_ci#define PN544_HCI_EVT_DEACTIVATED 0x03 828c2ecf20Sopenharmony_ci#define PN544_HCI_EVT_RCV_DATA 0x04 838c2ecf20Sopenharmony_ci#define PN544_HCI_EVT_CONTINUE_MI 0x05 848c2ecf20Sopenharmony_ci#define PN544_HCI_EVT_SWITCH_MODE 0x03 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define PN544_HCI_CMD_ATTREQUEST 0x12 878c2ecf20Sopenharmony_ci#define PN544_HCI_CMD_CONTINUE_ACTIVATION 0x13 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct nfc_hci_gate pn544_gates[] = { 908c2ecf20Sopenharmony_ci {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE}, 918c2ecf20Sopenharmony_ci {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, 928c2ecf20Sopenharmony_ci {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE}, 938c2ecf20Sopenharmony_ci {NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE}, 948c2ecf20Sopenharmony_ci {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE}, 958c2ecf20Sopenharmony_ci {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE}, 968c2ecf20Sopenharmony_ci {PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE}, 978c2ecf20Sopenharmony_ci {PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, 988c2ecf20Sopenharmony_ci {PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, 998c2ecf20Sopenharmony_ci {PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE}, 1008c2ecf20Sopenharmony_ci {PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, 1018c2ecf20Sopenharmony_ci {PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE}, 1028c2ecf20Sopenharmony_ci {PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, 1038c2ecf20Sopenharmony_ci {PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE}, 1048c2ecf20Sopenharmony_ci {PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE} 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Largest headroom needed for outgoing custom commands */ 1088c2ecf20Sopenharmony_ci#define PN544_CMDS_HEADROOM 2 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct pn544_hci_info { 1118c2ecf20Sopenharmony_ci struct nfc_phy_ops *phy_ops; 1128c2ecf20Sopenharmony_ci void *phy_id; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci struct nfc_hci_dev *hdev; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci enum pn544_state state; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci struct mutex info_lock; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci int async_cb_type; 1218c2ecf20Sopenharmony_ci data_exchange_cb_t async_cb; 1228c2ecf20Sopenharmony_ci void *async_cb_context; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci fw_download_t fw_download; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int pn544_hci_open(struct nfc_hci_dev *hdev) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); 1308c2ecf20Sopenharmony_ci int r = 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci mutex_lock(&info->info_lock); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (info->state != PN544_ST_COLD) { 1358c2ecf20Sopenharmony_ci r = -EBUSY; 1368c2ecf20Sopenharmony_ci goto out; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci r = info->phy_ops->enable(info->phy_id); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (r == 0) 1428c2ecf20Sopenharmony_ci info->state = PN544_ST_READY; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciout: 1458c2ecf20Sopenharmony_ci mutex_unlock(&info->info_lock); 1468c2ecf20Sopenharmony_ci return r; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void pn544_hci_close(struct nfc_hci_dev *hdev) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci mutex_lock(&info->info_lock); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (info->state == PN544_ST_COLD) 1568c2ecf20Sopenharmony_ci goto out; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci info->phy_ops->disable(info->phy_id); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci info->state = PN544_ST_COLD; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciout: 1638c2ecf20Sopenharmony_ci mutex_unlock(&info->info_lock); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int pn544_hci_ready(struct nfc_hci_dev *hdev) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct sk_buff *skb; 1698c2ecf20Sopenharmony_ci static struct hw_config { 1708c2ecf20Sopenharmony_ci u8 adr[2]; 1718c2ecf20Sopenharmony_ci u8 value; 1728c2ecf20Sopenharmony_ci } hw_config[] = { 1738c2ecf20Sopenharmony_ci {{0x9f, 0x9a}, 0x00}, 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci {{0x98, 0x10}, 0xbc}, 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci {{0x9e, 0x71}, 0x00}, 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci {{0x98, 0x09}, 0x00}, 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci {{0x9e, 0xb4}, 0x00}, 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci {{0x9c, 0x01}, 0x08}, 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci {{0x9e, 0xaa}, 0x01}, 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci {{0x9b, 0xd1}, 0x17}, 1888c2ecf20Sopenharmony_ci {{0x9b, 0xd2}, 0x58}, 1898c2ecf20Sopenharmony_ci {{0x9b, 0xd3}, 0x10}, 1908c2ecf20Sopenharmony_ci {{0x9b, 0xd4}, 0x47}, 1918c2ecf20Sopenharmony_ci {{0x9b, 0xd5}, 0x0c}, 1928c2ecf20Sopenharmony_ci {{0x9b, 0xd6}, 0x37}, 1938c2ecf20Sopenharmony_ci {{0x9b, 0xdd}, 0x33}, 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci {{0x9b, 0x84}, 0x00}, 1968c2ecf20Sopenharmony_ci {{0x99, 0x81}, 0x79}, 1978c2ecf20Sopenharmony_ci {{0x99, 0x31}, 0x79}, 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci {{0x98, 0x00}, 0x3f}, 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci {{0x9f, 0x09}, 0x02}, 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci {{0x9f, 0x0a}, 0x05}, 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci {{0x9e, 0xd1}, 0xa1}, 2068c2ecf20Sopenharmony_ci {{0x99, 0x23}, 0x01}, 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci {{0x9e, 0x74}, 0x00}, 2098c2ecf20Sopenharmony_ci {{0x9e, 0x90}, 0x00}, 2108c2ecf20Sopenharmony_ci {{0x9f, 0x28}, 0x10}, 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci {{0x9f, 0x35}, 0x04}, 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci {{0x9f, 0x36}, 0x11}, 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci {{0x9c, 0x31}, 0x00}, 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci {{0x9c, 0x32}, 0x00}, 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci {{0x9c, 0x19}, 0x0a}, 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci {{0x9c, 0x1a}, 0x0a}, 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci {{0x9c, 0x0c}, 0x00}, 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci {{0x9c, 0x0d}, 0x00}, 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci {{0x9c, 0x12}, 0x00}, 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci {{0x9c, 0x13}, 0x00}, 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci {{0x98, 0xa2}, 0x09}, 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci {{0x98, 0x93}, 0x00}, 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci {{0x98, 0x7d}, 0x08}, 2378c2ecf20Sopenharmony_ci {{0x98, 0x7e}, 0x00}, 2388c2ecf20Sopenharmony_ci {{0x9f, 0xc8}, 0x00}, 2398c2ecf20Sopenharmony_ci }; 2408c2ecf20Sopenharmony_ci struct hw_config *p = hw_config; 2418c2ecf20Sopenharmony_ci int count = ARRAY_SIZE(hw_config); 2428c2ecf20Sopenharmony_ci struct sk_buff *res_skb; 2438c2ecf20Sopenharmony_ci u8 param[4]; 2448c2ecf20Sopenharmony_ci int r; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci param[0] = 0; 2478c2ecf20Sopenharmony_ci while (count--) { 2488c2ecf20Sopenharmony_ci param[1] = p->adr[0]; 2498c2ecf20Sopenharmony_ci param[2] = p->adr[1]; 2508c2ecf20Sopenharmony_ci param[3] = p->value; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE, 2538c2ecf20Sopenharmony_ci param, 4, &res_skb); 2548c2ecf20Sopenharmony_ci if (r < 0) 2558c2ecf20Sopenharmony_ci return r; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (res_skb->len != 1) { 2588c2ecf20Sopenharmony_ci kfree_skb(res_skb); 2598c2ecf20Sopenharmony_ci return -EPROTO; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (res_skb->data[0] != p->value) { 2638c2ecf20Sopenharmony_ci kfree_skb(res_skb); 2648c2ecf20Sopenharmony_ci return -EIO; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci kfree_skb(res_skb); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci p++; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci param[0] = NFC_HCI_UICC_HOST_ID; 2738c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, 2748c2ecf20Sopenharmony_ci NFC_HCI_ADMIN_WHITELIST, param, 1); 2758c2ecf20Sopenharmony_ci if (r < 0) 2768c2ecf20Sopenharmony_ci return r; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci param[0] = 0x3d; 2798c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE, 2808c2ecf20Sopenharmony_ci PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1); 2818c2ecf20Sopenharmony_ci if (r < 0) 2828c2ecf20Sopenharmony_ci return r; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci param[0] = 0x0; 2858c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE, 2868c2ecf20Sopenharmony_ci PN544_RF_READER_A_AUTO_ACTIVATION, param, 1); 2878c2ecf20Sopenharmony_ci if (r < 0) 2888c2ecf20Sopenharmony_ci return r; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 2918c2ecf20Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 2928c2ecf20Sopenharmony_ci if (r < 0) 2938c2ecf20Sopenharmony_ci return r; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci param[0] = 0x1; 2968c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, 2978c2ecf20Sopenharmony_ci PN544_PL_NFCT_DEACTIVATED, param, 1); 2988c2ecf20Sopenharmony_ci if (r < 0) 2998c2ecf20Sopenharmony_ci return r; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci param[0] = 0x0; 3028c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, 3038c2ecf20Sopenharmony_ci PN544_PL_RDPHASES, param, 1); 3048c2ecf20Sopenharmony_ci if (r < 0) 3058c2ecf20Sopenharmony_ci return r; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, 3088c2ecf20Sopenharmony_ci PN544_ID_MGMT_FULL_VERSION_SW, &skb); 3098c2ecf20Sopenharmony_ci if (r < 0) 3108c2ecf20Sopenharmony_ci return r; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (skb->len != FULL_VERSION_LEN) { 3138c2ecf20Sopenharmony_ci kfree_skb(skb); 3148c2ecf20Sopenharmony_ci return -EINVAL; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ", 3188c2ecf20Sopenharmony_ci DUMP_PREFIX_NONE, 16, 1, 3198c2ecf20Sopenharmony_ci skb->data, FULL_VERSION_LEN, false); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci kfree_skb(skb); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return info->phy_ops->write(info->phy_id, skb); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int pn544_hci_start_poll(struct nfc_hci_dev *hdev, 3348c2ecf20Sopenharmony_ci u32 im_protocols, u32 tm_protocols) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci u8 phases = 0; 3378c2ecf20Sopenharmony_ci int r; 3388c2ecf20Sopenharmony_ci u8 duration[2]; 3398c2ecf20Sopenharmony_ci u8 activated; 3408c2ecf20Sopenharmony_ci u8 i_mode = 0x3f; /* Enable all supported modes */ 3418c2ecf20Sopenharmony_ci u8 t_mode = 0x0f; 3428c2ecf20Sopenharmony_ci u8 t_merge = 0x01; /* Enable merge by default */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n", 3458c2ecf20Sopenharmony_ci __func__, im_protocols, tm_protocols); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 3488c2ecf20Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 3498c2ecf20Sopenharmony_ci if (r < 0) 3508c2ecf20Sopenharmony_ci return r; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci duration[0] = 0x18; 3538c2ecf20Sopenharmony_ci duration[1] = 0x6a; 3548c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, 3558c2ecf20Sopenharmony_ci PN544_PL_EMULATION, duration, 2); 3568c2ecf20Sopenharmony_ci if (r < 0) 3578c2ecf20Sopenharmony_ci return r; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci activated = 0; 3608c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, 3618c2ecf20Sopenharmony_ci PN544_PL_NFCT_DEACTIVATED, &activated, 1); 3628c2ecf20Sopenharmony_ci if (r < 0) 3638c2ecf20Sopenharmony_ci return r; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK | 3668c2ecf20Sopenharmony_ci NFC_PROTO_JEWEL_MASK)) 3678c2ecf20Sopenharmony_ci phases |= 1; /* Type A */ 3688c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_FELICA_MASK) { 3698c2ecf20Sopenharmony_ci phases |= (1 << 2); /* Type F 212 */ 3708c2ecf20Sopenharmony_ci phases |= (1 << 3); /* Type F 424 */ 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci phases |= (1 << 5); /* NFC active */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, 3768c2ecf20Sopenharmony_ci PN544_PL_RDPHASES, &phases, 1); 3778c2ecf20Sopenharmony_ci if (r < 0) 3788c2ecf20Sopenharmony_ci return r; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { 3818c2ecf20Sopenharmony_ci hdev->gb = nfc_get_local_general_bytes(hdev->ndev, 3828c2ecf20Sopenharmony_ci &hdev->gb_len); 3838c2ecf20Sopenharmony_ci pr_debug("generate local bytes %p\n", hdev->gb); 3848c2ecf20Sopenharmony_ci if (hdev->gb == NULL || hdev->gb_len == 0) { 3858c2ecf20Sopenharmony_ci im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; 3868c2ecf20Sopenharmony_ci tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { 3918c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, 3928c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 3938c2ecf20Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 3948c2ecf20Sopenharmony_ci if (r < 0) 3958c2ecf20Sopenharmony_ci return r; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, 3988c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 3998c2ecf20Sopenharmony_ci PN544_DEP_MODE, &i_mode, 1); 4008c2ecf20Sopenharmony_ci if (r < 0) 4018c2ecf20Sopenharmony_ci return r; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, 4048c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 4058c2ecf20Sopenharmony_ci PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len); 4068c2ecf20Sopenharmony_ci if (r < 0) 4078c2ecf20Sopenharmony_ci return r; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, 4108c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 4118c2ecf20Sopenharmony_ci NFC_HCI_EVT_READER_REQUESTED, NULL, 0); 4128c2ecf20Sopenharmony_ci if (r < 0) 4138c2ecf20Sopenharmony_ci nfc_hci_send_event(hdev, 4148c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 4158c2ecf20Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { 4198c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, 4208c2ecf20Sopenharmony_ci PN544_DEP_MODE, &t_mode, 1); 4218c2ecf20Sopenharmony_ci if (r < 0) 4228c2ecf20Sopenharmony_ci return r; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, 4258c2ecf20Sopenharmony_ci PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len); 4268c2ecf20Sopenharmony_ci if (r < 0) 4278c2ecf20Sopenharmony_ci return r; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, 4308c2ecf20Sopenharmony_ci PN544_DEP_MERGE, &t_merge, 1); 4318c2ecf20Sopenharmony_ci if (r < 0) 4328c2ecf20Sopenharmony_ci return r; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 4368c2ecf20Sopenharmony_ci NFC_HCI_EVT_READER_REQUESTED, NULL, 0); 4378c2ecf20Sopenharmony_ci if (r < 0) 4388c2ecf20Sopenharmony_ci nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 4398c2ecf20Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return r; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev, 4458c2ecf20Sopenharmony_ci struct nfc_target *target, u8 comm_mode, 4468c2ecf20Sopenharmony_ci u8 *gb, size_t gb_len) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct sk_buff *rgb_skb = NULL; 4498c2ecf20Sopenharmony_ci int r; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci r = nfc_hci_get_param(hdev, target->hci_reader_gate, 4528c2ecf20Sopenharmony_ci PN544_DEP_ATR_RES, &rgb_skb); 4538c2ecf20Sopenharmony_ci if (r < 0) 4548c2ecf20Sopenharmony_ci return r; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) { 4578c2ecf20Sopenharmony_ci r = -EPROTO; 4588c2ecf20Sopenharmony_ci goto exit; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET, 4618c2ecf20Sopenharmony_ci 16, 1, rgb_skb->data, rgb_skb->len, true); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data, 4648c2ecf20Sopenharmony_ci rgb_skb->len); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (r == 0) 4678c2ecf20Sopenharmony_ci r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode, 4688c2ecf20Sopenharmony_ci NFC_RF_INITIATOR); 4698c2ecf20Sopenharmony_ciexit: 4708c2ecf20Sopenharmony_ci kfree_skb(rgb_skb); 4718c2ecf20Sopenharmony_ci return r; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE, 4788c2ecf20Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, 4828c2ecf20Sopenharmony_ci struct nfc_target *target) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci switch (gate) { 4858c2ecf20Sopenharmony_ci case PN544_RF_READER_F_GATE: 4868c2ecf20Sopenharmony_ci target->supported_protocols = NFC_PROTO_FELICA_MASK; 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci case PN544_RF_READER_JEWEL_GATE: 4898c2ecf20Sopenharmony_ci target->supported_protocols = NFC_PROTO_JEWEL_MASK; 4908c2ecf20Sopenharmony_ci target->sens_res = 0x0c00; 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case PN544_RF_READER_NFCIP1_INITIATOR_GATE: 4938c2ecf20Sopenharmony_ci target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci default: 4968c2ecf20Sopenharmony_ci return -EPROTO; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev, 5038c2ecf20Sopenharmony_ci u8 gate, 5048c2ecf20Sopenharmony_ci struct nfc_target *target) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct sk_buff *uid_skb; 5078c2ecf20Sopenharmony_ci int r = 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) 5108c2ecf20Sopenharmony_ci return r; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) { 5138c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, 5148c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 5158c2ecf20Sopenharmony_ci PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL); 5168c2ecf20Sopenharmony_ci if (r < 0) 5178c2ecf20Sopenharmony_ci return r; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE; 5208c2ecf20Sopenharmony_ci } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { 5218c2ecf20Sopenharmony_ci if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && 5228c2ecf20Sopenharmony_ci target->nfcid1_len != 10) 5238c2ecf20Sopenharmony_ci return -EPROTO; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, 5268c2ecf20Sopenharmony_ci PN544_RF_READER_CMD_ACTIVATE_NEXT, 5278c2ecf20Sopenharmony_ci target->nfcid1, target->nfcid1_len, NULL); 5288c2ecf20Sopenharmony_ci } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) { 5298c2ecf20Sopenharmony_ci r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE, 5308c2ecf20Sopenharmony_ci PN544_FELICA_ID, &uid_skb); 5318c2ecf20Sopenharmony_ci if (r < 0) 5328c2ecf20Sopenharmony_ci return r; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (uid_skb->len != 8) { 5358c2ecf20Sopenharmony_ci kfree_skb(uid_skb); 5368c2ecf20Sopenharmony_ci return -EPROTO; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Type F NFC-DEP IDm has prefix 0x01FE */ 5408c2ecf20Sopenharmony_ci if ((uid_skb->data[0] == 0x01) && (uid_skb->data[1] == 0xfe)) { 5418c2ecf20Sopenharmony_ci kfree_skb(uid_skb); 5428c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, 5438c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE, 5448c2ecf20Sopenharmony_ci PN544_HCI_CMD_CONTINUE_ACTIVATION, 5458c2ecf20Sopenharmony_ci NULL, 0, NULL); 5468c2ecf20Sopenharmony_ci if (r < 0) 5478c2ecf20Sopenharmony_ci return r; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; 5508c2ecf20Sopenharmony_ci target->hci_reader_gate = 5518c2ecf20Sopenharmony_ci PN544_RF_READER_NFCIP1_INITIATOR_GATE; 5528c2ecf20Sopenharmony_ci } else { 5538c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE, 5548c2ecf20Sopenharmony_ci PN544_RF_READER_CMD_ACTIVATE_NEXT, 5558c2ecf20Sopenharmony_ci uid_skb->data, uid_skb->len, NULL); 5568c2ecf20Sopenharmony_ci kfree_skb(uid_skb); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) { 5598c2ecf20Sopenharmony_ci /* 5608c2ecf20Sopenharmony_ci * TODO: maybe other ISO 14443 require some kind of continue 5618c2ecf20Sopenharmony_ci * activation, but for now we've seen only this one below. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */ 5648c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, 5658c2ecf20Sopenharmony_ci PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION, 5668c2ecf20Sopenharmony_ci NULL, 0, NULL); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return r; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci#define PN544_CB_TYPE_READER_F 1 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb, 5758c2ecf20Sopenharmony_ci int err) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct pn544_hci_info *info = context; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci switch (info->async_cb_type) { 5808c2ecf20Sopenharmony_ci case PN544_CB_TYPE_READER_F: 5818c2ecf20Sopenharmony_ci if (err == 0) 5828c2ecf20Sopenharmony_ci skb_pull(skb, 1); 5838c2ecf20Sopenharmony_ci info->async_cb(info->async_cb_context, skb, err); 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci default: 5868c2ecf20Sopenharmony_ci if (err == 0) 5878c2ecf20Sopenharmony_ci kfree_skb(skb); 5888c2ecf20Sopenharmony_ci break; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci#define MIFARE_CMD_AUTH_KEY_A 0x60 5938c2ecf20Sopenharmony_ci#define MIFARE_CMD_AUTH_KEY_B 0x61 5948c2ecf20Sopenharmony_ci#define MIFARE_CMD_HEADER 2 5958c2ecf20Sopenharmony_ci#define MIFARE_UID_LEN 4 5968c2ecf20Sopenharmony_ci#define MIFARE_KEY_LEN 6 5978c2ecf20Sopenharmony_ci#define MIFARE_CMD_LEN 12 5988c2ecf20Sopenharmony_ci/* 5998c2ecf20Sopenharmony_ci * Returns: 6008c2ecf20Sopenharmony_ci * <= 0: driver handled the data exchange 6018c2ecf20Sopenharmony_ci * 1: driver doesn't especially handle, please do standard processing 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_cistatic int pn544_hci_im_transceive(struct nfc_hci_dev *hdev, 6048c2ecf20Sopenharmony_ci struct nfc_target *target, 6058c2ecf20Sopenharmony_ci struct sk_buff *skb, data_exchange_cb_t cb, 6068c2ecf20Sopenharmony_ci void *cb_context) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, 6118c2ecf20Sopenharmony_ci target->hci_reader_gate); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci switch (target->hci_reader_gate) { 6148c2ecf20Sopenharmony_ci case NFC_HCI_RF_READER_A_GATE: 6158c2ecf20Sopenharmony_ci if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { 6168c2ecf20Sopenharmony_ci /* 6178c2ecf20Sopenharmony_ci * It seems that pn544 is inverting key and UID for 6188c2ecf20Sopenharmony_ci * MIFARE authentication commands. 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_ci if (skb->len == MIFARE_CMD_LEN && 6218c2ecf20Sopenharmony_ci (skb->data[0] == MIFARE_CMD_AUTH_KEY_A || 6228c2ecf20Sopenharmony_ci skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) { 6238c2ecf20Sopenharmony_ci u8 uid[MIFARE_UID_LEN]; 6248c2ecf20Sopenharmony_ci u8 *data = skb->data + MIFARE_CMD_HEADER; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci memcpy(uid, data + MIFARE_KEY_LEN, 6278c2ecf20Sopenharmony_ci MIFARE_UID_LEN); 6288c2ecf20Sopenharmony_ci memmove(data + MIFARE_UID_LEN, data, 6298c2ecf20Sopenharmony_ci MIFARE_KEY_LEN); 6308c2ecf20Sopenharmony_ci memcpy(data, uid, MIFARE_UID_LEN); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return nfc_hci_send_cmd_async(hdev, 6348c2ecf20Sopenharmony_ci target->hci_reader_gate, 6358c2ecf20Sopenharmony_ci PN544_MIFARE_CMD, 6368c2ecf20Sopenharmony_ci skb->data, skb->len, 6378c2ecf20Sopenharmony_ci cb, cb_context); 6388c2ecf20Sopenharmony_ci } else 6398c2ecf20Sopenharmony_ci return 1; 6408c2ecf20Sopenharmony_ci case PN544_RF_READER_F_GATE: 6418c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = 0; 6428c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = 0; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci info->async_cb_type = PN544_CB_TYPE_READER_F; 6458c2ecf20Sopenharmony_ci info->async_cb = cb; 6468c2ecf20Sopenharmony_ci info->async_cb_context = cb_context; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, 6498c2ecf20Sopenharmony_ci PN544_FELICA_RAW, skb->data, 6508c2ecf20Sopenharmony_ci skb->len, 6518c2ecf20Sopenharmony_ci pn544_hci_data_exchange_cb, info); 6528c2ecf20Sopenharmony_ci case PN544_RF_READER_JEWEL_GATE: 6538c2ecf20Sopenharmony_ci return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, 6548c2ecf20Sopenharmony_ci PN544_JEWEL_RAW_CMD, skb->data, 6558c2ecf20Sopenharmony_ci skb->len, cb, cb_context); 6568c2ecf20Sopenharmony_ci case PN544_RF_READER_NFCIP1_INITIATOR_GATE: 6578c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = 0; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return nfc_hci_send_event(hdev, target->hci_reader_gate, 6608c2ecf20Sopenharmony_ci PN544_HCI_EVT_SND_DATA, skb->data, 6618c2ecf20Sopenharmony_ci skb->len); 6628c2ecf20Sopenharmony_ci default: 6638c2ecf20Sopenharmony_ci return 1; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci int r; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Set default false for multiple information chaining */ 6728c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = 0; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, 6758c2ecf20Sopenharmony_ci PN544_HCI_EVT_SND_DATA, skb->data, skb->len); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci kfree_skb(skb); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return r; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int pn544_hci_check_presence(struct nfc_hci_dev *hdev, 6838c2ecf20Sopenharmony_ci struct nfc_target *target) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci pr_debug("supported protocol %d\n", target->supported_protocols); 6868c2ecf20Sopenharmony_ci if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK | 6878c2ecf20Sopenharmony_ci NFC_PROTO_ISO14443_B_MASK)) { 6888c2ecf20Sopenharmony_ci return nfc_hci_send_cmd(hdev, target->hci_reader_gate, 6898c2ecf20Sopenharmony_ci PN544_RF_READER_CMD_PRESENCE_CHECK, 6908c2ecf20Sopenharmony_ci NULL, 0, NULL); 6918c2ecf20Sopenharmony_ci } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { 6928c2ecf20Sopenharmony_ci if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && 6938c2ecf20Sopenharmony_ci target->nfcid1_len != 10) 6948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, 6978c2ecf20Sopenharmony_ci PN544_RF_READER_CMD_ACTIVATE_NEXT, 6988c2ecf20Sopenharmony_ci target->nfcid1, target->nfcid1_len, NULL); 6998c2ecf20Sopenharmony_ci } else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK | 7008c2ecf20Sopenharmony_ci NFC_PROTO_FELICA_MASK)) { 7018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7028c2ecf20Sopenharmony_ci } else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) { 7038c2ecf20Sopenharmony_ci return nfc_hci_send_cmd(hdev, target->hci_reader_gate, 7048c2ecf20Sopenharmony_ci PN544_HCI_CMD_ATTREQUEST, 7058c2ecf20Sopenharmony_ci NULL, 0, NULL); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return 0; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* 7128c2ecf20Sopenharmony_ci * Returns: 7138c2ecf20Sopenharmony_ci * <= 0: driver handled the event, skb consumed 7148c2ecf20Sopenharmony_ci * 1: driver does not handle the event, please do standard processing 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_cistatic int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, 7178c2ecf20Sopenharmony_ci struct sk_buff *skb) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct sk_buff *rgb_skb = NULL; 7208c2ecf20Sopenharmony_ci u8 gate = hdev->pipes[pipe].gate; 7218c2ecf20Sopenharmony_ci int r; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci pr_debug("hci event %d\n", event); 7248c2ecf20Sopenharmony_ci switch (event) { 7258c2ecf20Sopenharmony_ci case PN544_HCI_EVT_ACTIVATED: 7268c2ecf20Sopenharmony_ci if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) { 7278c2ecf20Sopenharmony_ci r = nfc_hci_target_discovered(hdev, gate); 7288c2ecf20Sopenharmony_ci } else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) { 7298c2ecf20Sopenharmony_ci r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ, 7308c2ecf20Sopenharmony_ci &rgb_skb); 7318c2ecf20Sopenharmony_ci if (r < 0) 7328c2ecf20Sopenharmony_ci goto exit; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, 7358c2ecf20Sopenharmony_ci NFC_COMM_PASSIVE, rgb_skb->data, 7368c2ecf20Sopenharmony_ci rgb_skb->len); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci kfree_skb(rgb_skb); 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci r = -EINVAL; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci case PN544_HCI_EVT_DEACTIVATED: 7448c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION, 7458c2ecf20Sopenharmony_ci NULL, 0); 7468c2ecf20Sopenharmony_ci break; 7478c2ecf20Sopenharmony_ci case PN544_HCI_EVT_RCV_DATA: 7488c2ecf20Sopenharmony_ci if (skb->len < 2) { 7498c2ecf20Sopenharmony_ci r = -EPROTO; 7508c2ecf20Sopenharmony_ci goto exit; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (skb->data[0] != 0) { 7548c2ecf20Sopenharmony_ci pr_debug("data0 %d\n", skb->data[0]); 7558c2ecf20Sopenharmony_ci r = -EPROTO; 7568c2ecf20Sopenharmony_ci goto exit; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci skb_pull(skb, 2); 7608c2ecf20Sopenharmony_ci return nfc_tm_data_received(hdev->ndev, skb); 7618c2ecf20Sopenharmony_ci default: 7628c2ecf20Sopenharmony_ci return 1; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ciexit: 7668c2ecf20Sopenharmony_ci kfree_skb(skb); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci return r; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic int pn544_hci_fw_download(struct nfc_hci_dev *hdev, 7728c2ecf20Sopenharmony_ci const char *firmware_name) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (info->fw_download == NULL) 7778c2ecf20Sopenharmony_ci return -ENOTSUPP; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return info->fw_download(info->phy_id, firmware_name, hdev->sw_romlib); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int pn544_hci_discover_se(struct nfc_hci_dev *hdev) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci u32 se_idx = 0; 7858c2ecf20Sopenharmony_ci u8 ese_mode = 0x01; /* Default mode */ 7868c2ecf20Sopenharmony_ci struct sk_buff *res_skb; 7878c2ecf20Sopenharmony_ci int r; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP, 7908c2ecf20Sopenharmony_ci NULL, 0, &res_skb); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (r == 0) { 7938c2ecf20Sopenharmony_ci if (res_skb->len == 2 && res_skb->data[0] == 0x00) 7948c2ecf20Sopenharmony_ci nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci kfree_skb(res_skb); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE, 8008c2ecf20Sopenharmony_ci PN544_HCI_EVT_SWITCH_MODE, 8018c2ecf20Sopenharmony_ci &ese_mode, 1); 8028c2ecf20Sopenharmony_ci if (r == 0) 8038c2ecf20Sopenharmony_ci nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return !se_idx; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci#define PN544_SE_MODE_OFF 0x00 8098c2ecf20Sopenharmony_ci#define PN544_SE_MODE_ON 0x01 8108c2ecf20Sopenharmony_cistatic int pn544_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct nfc_se *se; 8138c2ecf20Sopenharmony_ci u8 enable = PN544_SE_MODE_ON; 8148c2ecf20Sopenharmony_ci static struct uicc_gatelist { 8158c2ecf20Sopenharmony_ci u8 head; 8168c2ecf20Sopenharmony_ci u8 adr[2]; 8178c2ecf20Sopenharmony_ci u8 value; 8188c2ecf20Sopenharmony_ci } uicc_gatelist[] = { 8198c2ecf20Sopenharmony_ci {0x00, {0x9e, 0xd9}, 0x23}, 8208c2ecf20Sopenharmony_ci {0x00, {0x9e, 0xda}, 0x21}, 8218c2ecf20Sopenharmony_ci {0x00, {0x9e, 0xdb}, 0x22}, 8228c2ecf20Sopenharmony_ci {0x00, {0x9e, 0xdc}, 0x24}, 8238c2ecf20Sopenharmony_ci }; 8248c2ecf20Sopenharmony_ci struct uicc_gatelist *p = uicc_gatelist; 8258c2ecf20Sopenharmony_ci int count = ARRAY_SIZE(uicc_gatelist); 8268c2ecf20Sopenharmony_ci struct sk_buff *res_skb; 8278c2ecf20Sopenharmony_ci int r; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci se = nfc_find_se(hdev->ndev, se_idx); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci switch (se->type) { 8328c2ecf20Sopenharmony_ci case NFC_SE_UICC: 8338c2ecf20Sopenharmony_ci while (count--) { 8348c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, 8358c2ecf20Sopenharmony_ci PN544_WRITE, (u8 *)p, 4, &res_skb); 8368c2ecf20Sopenharmony_ci if (r < 0) 8378c2ecf20Sopenharmony_ci return r; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (res_skb->len != 1) { 8408c2ecf20Sopenharmony_ci kfree_skb(res_skb); 8418c2ecf20Sopenharmony_ci return -EPROTO; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (res_skb->data[0] != p->value) { 8458c2ecf20Sopenharmony_ci kfree_skb(res_skb); 8468c2ecf20Sopenharmony_ci return -EIO; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci kfree_skb(res_skb); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci p++; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE, 8558c2ecf20Sopenharmony_ci PN544_SWP_DEFAULT_MODE, &enable, 1); 8568c2ecf20Sopenharmony_ci case NFC_SE_EMBEDDED: 8578c2ecf20Sopenharmony_ci return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE, 8588c2ecf20Sopenharmony_ci PN544_NFC_ESE_DEFAULT_MODE, &enable, 1); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci default: 8618c2ecf20Sopenharmony_ci return -EINVAL; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int pn544_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct nfc_se *se; 8688c2ecf20Sopenharmony_ci u8 disable = PN544_SE_MODE_OFF; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci se = nfc_find_se(hdev->ndev, se_idx); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci switch (se->type) { 8738c2ecf20Sopenharmony_ci case NFC_SE_UICC: 8748c2ecf20Sopenharmony_ci return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE, 8758c2ecf20Sopenharmony_ci PN544_SWP_DEFAULT_MODE, &disable, 1); 8768c2ecf20Sopenharmony_ci case NFC_SE_EMBEDDED: 8778c2ecf20Sopenharmony_ci return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE, 8788c2ecf20Sopenharmony_ci PN544_NFC_ESE_DEFAULT_MODE, &disable, 1); 8798c2ecf20Sopenharmony_ci default: 8808c2ecf20Sopenharmony_ci return -EINVAL; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic struct nfc_hci_ops pn544_hci_ops = { 8858c2ecf20Sopenharmony_ci .open = pn544_hci_open, 8868c2ecf20Sopenharmony_ci .close = pn544_hci_close, 8878c2ecf20Sopenharmony_ci .hci_ready = pn544_hci_ready, 8888c2ecf20Sopenharmony_ci .xmit = pn544_hci_xmit, 8898c2ecf20Sopenharmony_ci .start_poll = pn544_hci_start_poll, 8908c2ecf20Sopenharmony_ci .dep_link_up = pn544_hci_dep_link_up, 8918c2ecf20Sopenharmony_ci .dep_link_down = pn544_hci_dep_link_down, 8928c2ecf20Sopenharmony_ci .target_from_gate = pn544_hci_target_from_gate, 8938c2ecf20Sopenharmony_ci .complete_target_discovered = pn544_hci_complete_target_discovered, 8948c2ecf20Sopenharmony_ci .im_transceive = pn544_hci_im_transceive, 8958c2ecf20Sopenharmony_ci .tm_send = pn544_hci_tm_send, 8968c2ecf20Sopenharmony_ci .check_presence = pn544_hci_check_presence, 8978c2ecf20Sopenharmony_ci .event_received = pn544_hci_event_received, 8988c2ecf20Sopenharmony_ci .fw_download = pn544_hci_fw_download, 8998c2ecf20Sopenharmony_ci .discover_se = pn544_hci_discover_se, 9008c2ecf20Sopenharmony_ci .enable_se = pn544_hci_enable_se, 9018c2ecf20Sopenharmony_ci .disable_se = pn544_hci_disable_se, 9028c2ecf20Sopenharmony_ci}; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ciint pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, 9058c2ecf20Sopenharmony_ci int phy_headroom, int phy_tailroom, int phy_payload, 9068c2ecf20Sopenharmony_ci fw_download_t fw_download, struct nfc_hci_dev **hdev) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct pn544_hci_info *info; 9098c2ecf20Sopenharmony_ci u32 protocols; 9108c2ecf20Sopenharmony_ci struct nfc_hci_init_data init_data; 9118c2ecf20Sopenharmony_ci int r; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL); 9148c2ecf20Sopenharmony_ci if (!info) { 9158c2ecf20Sopenharmony_ci r = -ENOMEM; 9168c2ecf20Sopenharmony_ci goto err_info_alloc; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci info->phy_ops = phy_ops; 9208c2ecf20Sopenharmony_ci info->phy_id = phy_id; 9218c2ecf20Sopenharmony_ci info->fw_download = fw_download; 9228c2ecf20Sopenharmony_ci info->state = PN544_ST_COLD; 9238c2ecf20Sopenharmony_ci mutex_init(&info->info_lock); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci init_data.gate_count = ARRAY_SIZE(pn544_gates); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates)); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* 9308c2ecf20Sopenharmony_ci * TODO: Session id must include the driver name + some bus addr 9318c2ecf20Sopenharmony_ci * persistent info to discriminate 2 identical chips 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_ci strcpy(init_data.session_id, "ID544HCI"); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci protocols = NFC_PROTO_JEWEL_MASK | 9368c2ecf20Sopenharmony_ci NFC_PROTO_MIFARE_MASK | 9378c2ecf20Sopenharmony_ci NFC_PROTO_FELICA_MASK | 9388c2ecf20Sopenharmony_ci NFC_PROTO_ISO14443_MASK | 9398c2ecf20Sopenharmony_ci NFC_PROTO_ISO14443_B_MASK | 9408c2ecf20Sopenharmony_ci NFC_PROTO_NFC_DEP_MASK; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0, 9438c2ecf20Sopenharmony_ci protocols, llc_name, 9448c2ecf20Sopenharmony_ci phy_headroom + PN544_CMDS_HEADROOM, 9458c2ecf20Sopenharmony_ci phy_tailroom, phy_payload); 9468c2ecf20Sopenharmony_ci if (!info->hdev) { 9478c2ecf20Sopenharmony_ci pr_err("Cannot allocate nfc hdev\n"); 9488c2ecf20Sopenharmony_ci r = -ENOMEM; 9498c2ecf20Sopenharmony_ci goto err_alloc_hdev; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci nfc_hci_set_clientdata(info->hdev, info); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci r = nfc_hci_register_device(info->hdev); 9558c2ecf20Sopenharmony_ci if (r) 9568c2ecf20Sopenharmony_ci goto err_regdev; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci *hdev = info->hdev; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return 0; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cierr_regdev: 9638c2ecf20Sopenharmony_ci nfc_hci_free_device(info->hdev); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cierr_alloc_hdev: 9668c2ecf20Sopenharmony_ci kfree(info); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cierr_info_alloc: 9698c2ecf20Sopenharmony_ci return r; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pn544_hci_probe); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_civoid pn544_hci_remove(struct nfc_hci_dev *hdev) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci nfc_hci_unregister_device(hdev); 9788c2ecf20Sopenharmony_ci nfc_hci_free_device(hdev); 9798c2ecf20Sopenharmony_ci kfree(info); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pn544_hci_remove); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 9848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 985