18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * HCI based Driver for Inside Secure microread NFC Chip 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/crc-ccitt.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/nfc.h> 168c2ecf20Sopenharmony_ci#include <net/nfc/nfc.h> 178c2ecf20Sopenharmony_ci#include <net/nfc/hci.h> 188c2ecf20Sopenharmony_ci#include <net/nfc/llc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "microread.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Proprietary gates, events, commands and registers */ 238c2ecf20Sopenharmony_ci/* Admin */ 248c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE 258c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MGT 0x01 268c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_OS 0x02 278c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_TESTRF 0x03 288c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE 298c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE 308c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Reader */ 338c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_GEN 0x10 348c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE 358c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12 368c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE 378c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14 388c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15 398c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16 408c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17 418c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_BPRIME 0x18 428c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Card */ 458c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_GEN 0x20 468c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_ISO_B 0x21 478c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_BPRIME 0x22 488c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_ISO_A 0x23 498c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24 508c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25 518c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26 528c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27 538c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28 548c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* P2P */ 578c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_P2P_GEN 0x30 588c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_P2P_TARGET 0x31 598c2ecf20Sopenharmony_ci#define MICROREAD_PAR_P2P_TARGET_MODE 0x01 608c2ecf20Sopenharmony_ci#define MICROREAD_PAR_P2P_TARGET_GT 0x04 618c2ecf20Sopenharmony_ci#define MICROREAD_GATE_ID_P2P_INITIATOR 0x32 628c2ecf20Sopenharmony_ci#define MICROREAD_PAR_P2P_INITIATOR_GI 0x01 638c2ecf20Sopenharmony_ci#define MICROREAD_PAR_P2P_INITIATOR_GT 0x03 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Those pipes are created/opened by default in the chip */ 668c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_LMS 0x00 678c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_ADMIN 0x01 688c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_MGT 0x02 698c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_OS 0x03 708c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04 718c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_IDT 0x05 728c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08 738c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09 748c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A 758c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B 768c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C 778c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D 788c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E 798c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F 808c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10 818c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11 828c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12 838c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13 848c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14 858c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15 868c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16 878c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17 888c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18 898c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B 908c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C 918c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D 928c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E 938c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F 948c2ecf20Sopenharmony_ci#define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Events */ 978c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED 988c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D 998c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A_ATQA 0 1008c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A_SAK 2 1018c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A_LEN 3 1028c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A_UID 4 1038c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A3_ATQA 0 1048c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A3_SAK 2 1058c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A3_LEN 3 1068c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_A3_UID 4 1078c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_B_UID 0 1088c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_T1_ATQA 0 1098c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_T1_UID 4 1108c2ecf20Sopenharmony_ci#define MICROREAD_EMCF_T3_UID 0 1118c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED 1128c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E 1138c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION 1148c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F 1158c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED 1168c2ecf20Sopenharmony_ci#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20 1178c2ecf20Sopenharmony_ci#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21 1188c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MCARD_FIELD_ON 0x11 1198c2ecf20Sopenharmony_ci#define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13 1208c2ecf20Sopenharmony_ci#define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12 1218c2ecf20Sopenharmony_ci#define MICROREAD_EVT_MCARD_FIELD_OFF 0x14 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* Commands */ 1248c2ecf20Sopenharmony_ci#define MICROREAD_CMD_MREAD_EXCHANGE 0x10 1258c2ecf20Sopenharmony_ci#define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* Hosts IDs */ 1288c2ecf20Sopenharmony_ci#define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID 1298c2ecf20Sopenharmony_ci#define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID 1308c2ecf20Sopenharmony_ci#define MICROREAD_ELT_ID_SE1 0x03 1318c2ecf20Sopenharmony_ci#define MICROREAD_ELT_ID_SE2 0x04 1328c2ecf20Sopenharmony_ci#define MICROREAD_ELT_ID_SE3 0x05 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic struct nfc_hci_gate microread_gates[] = { 1358c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN}, 1368c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK}, 1378c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT}, 1388c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS}, 1398c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B}, 1408c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A}, 1418c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3}, 1428c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT}, 1438c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS}, 1448c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1}, 1458c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3}, 1468c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET}, 1478c2ecf20Sopenharmony_ci {MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR} 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* Largest headroom needed for outgoing custom commands */ 1518c2ecf20Sopenharmony_ci#define MICROREAD_CMDS_HEADROOM 2 1528c2ecf20Sopenharmony_ci#define MICROREAD_CMD_TAILROOM 2 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistruct microread_info { 1558c2ecf20Sopenharmony_ci struct nfc_phy_ops *phy_ops; 1568c2ecf20Sopenharmony_ci void *phy_id; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci struct nfc_hci_dev *hdev; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci int async_cb_type; 1618c2ecf20Sopenharmony_ci data_exchange_cb_t async_cb; 1628c2ecf20Sopenharmony_ci void *async_cb_context; 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int microread_open(struct nfc_hci_dev *hdev) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct microread_info *info = nfc_hci_get_clientdata(hdev); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return info->phy_ops->enable(info->phy_id); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void microread_close(struct nfc_hci_dev *hdev) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct microread_info *info = nfc_hci_get_clientdata(hdev); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci info->phy_ops->disable(info->phy_id); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int microread_hci_ready(struct nfc_hci_dev *hdev) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int r; 1828c2ecf20Sopenharmony_ci u8 param[4]; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci param[0] = 0x03; 1858c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, 1868c2ecf20Sopenharmony_ci MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL); 1878c2ecf20Sopenharmony_ci if (r) 1888c2ecf20Sopenharmony_ci return r; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3, 1918c2ecf20Sopenharmony_ci MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL); 1928c2ecf20Sopenharmony_ci if (r) 1938c2ecf20Sopenharmony_ci return r; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci param[0] = 0x00; 1968c2ecf20Sopenharmony_ci param[1] = 0x03; 1978c2ecf20Sopenharmony_ci param[2] = 0x00; 1988c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B, 1998c2ecf20Sopenharmony_ci MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL); 2008c2ecf20Sopenharmony_ci if (r) 2018c2ecf20Sopenharmony_ci return r; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1, 2048c2ecf20Sopenharmony_ci MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL); 2058c2ecf20Sopenharmony_ci if (r) 2068c2ecf20Sopenharmony_ci return r; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci param[0] = 0xFF; 2098c2ecf20Sopenharmony_ci param[1] = 0xFF; 2108c2ecf20Sopenharmony_ci param[2] = 0x00; 2118c2ecf20Sopenharmony_ci param[3] = 0x00; 2128c2ecf20Sopenharmony_ci r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3, 2138c2ecf20Sopenharmony_ci MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return r; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct microread_info *info = nfc_hci_get_clientdata(hdev); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return info->phy_ops->write(info->phy_id, skb); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int microread_start_poll(struct nfc_hci_dev *hdev, 2268c2ecf20Sopenharmony_ci u32 im_protocols, u32 tm_protocols) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int r; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci u8 param[2]; 2318c2ecf20Sopenharmony_ci u8 mode; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci param[0] = 0x00; 2348c2ecf20Sopenharmony_ci param[1] = 0x00; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_ISO14443_MASK) 2378c2ecf20Sopenharmony_ci param[0] |= (1 << 2); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_ISO14443_B_MASK) 2408c2ecf20Sopenharmony_ci param[0] |= 1; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_MIFARE_MASK) 2438c2ecf20Sopenharmony_ci param[1] |= 1; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_JEWEL_MASK) 2468c2ecf20Sopenharmony_ci param[0] |= (1 << 1); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_FELICA_MASK) 2498c2ecf20Sopenharmony_ci param[0] |= (1 << 5); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_NFC_DEP_MASK) 2528c2ecf20Sopenharmony_ci param[1] |= (1 << 1); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { 2558c2ecf20Sopenharmony_ci hdev->gb = nfc_get_local_general_bytes(hdev->ndev, 2568c2ecf20Sopenharmony_ci &hdev->gb_len); 2578c2ecf20Sopenharmony_ci if (hdev->gb == NULL || hdev->gb_len == 0) { 2588c2ecf20Sopenharmony_ci im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; 2598c2ecf20Sopenharmony_ci tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, 2648c2ecf20Sopenharmony_ci MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0); 2658c2ecf20Sopenharmony_ci if (r) 2668c2ecf20Sopenharmony_ci return r; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci mode = 0xff; 2698c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, 2708c2ecf20Sopenharmony_ci MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); 2718c2ecf20Sopenharmony_ci if (r) 2728c2ecf20Sopenharmony_ci return r; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { 2758c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR, 2768c2ecf20Sopenharmony_ci MICROREAD_PAR_P2P_INITIATOR_GI, 2778c2ecf20Sopenharmony_ci hdev->gb, hdev->gb_len); 2788c2ecf20Sopenharmony_ci if (r) 2798c2ecf20Sopenharmony_ci return r; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { 2838c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, 2848c2ecf20Sopenharmony_ci MICROREAD_PAR_P2P_TARGET_GT, 2858c2ecf20Sopenharmony_ci hdev->gb, hdev->gb_len); 2868c2ecf20Sopenharmony_ci if (r) 2878c2ecf20Sopenharmony_ci return r; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci mode = 0x02; 2908c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, 2918c2ecf20Sopenharmony_ci MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); 2928c2ecf20Sopenharmony_ci if (r) 2938c2ecf20Sopenharmony_ci return r; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, 2978c2ecf20Sopenharmony_ci MICROREAD_EVT_MREAD_DISCOVERY_START_SOME, 2988c2ecf20Sopenharmony_ci param, 2); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int microread_dep_link_up(struct nfc_hci_dev *hdev, 3028c2ecf20Sopenharmony_ci struct nfc_target *target, u8 comm_mode, 3038c2ecf20Sopenharmony_ci u8 *gb, size_t gb_len) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct sk_buff *rgb_skb = NULL; 3068c2ecf20Sopenharmony_ci int r; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci r = nfc_hci_get_param(hdev, target->hci_reader_gate, 3098c2ecf20Sopenharmony_ci MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb); 3108c2ecf20Sopenharmony_ci if (r < 0) 3118c2ecf20Sopenharmony_ci return r; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) { 3148c2ecf20Sopenharmony_ci r = -EPROTO; 3158c2ecf20Sopenharmony_ci goto exit; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data, 3198c2ecf20Sopenharmony_ci rgb_skb->len); 3208c2ecf20Sopenharmony_ci if (r == 0) 3218c2ecf20Sopenharmony_ci r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode, 3228c2ecf20Sopenharmony_ci NFC_RF_INITIATOR); 3238c2ecf20Sopenharmony_ciexit: 3248c2ecf20Sopenharmony_ci kfree_skb(rgb_skb); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return r; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int microread_dep_link_down(struct nfc_hci_dev *hdev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR, 3328c2ecf20Sopenharmony_ci MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, 3368c2ecf20Sopenharmony_ci struct nfc_target *target) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci switch (gate) { 3398c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_P2P_INITIATOR: 3408c2ecf20Sopenharmony_ci target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci default: 3438c2ecf20Sopenharmony_ci return -EPROTO; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int microread_complete_target_discovered(struct nfc_hci_dev *hdev, 3508c2ecf20Sopenharmony_ci u8 gate, 3518c2ecf20Sopenharmony_ci struct nfc_target *target) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci#define MICROREAD_CB_TYPE_READER_ALL 1 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void microread_im_transceive_cb(void *context, struct sk_buff *skb, 3598c2ecf20Sopenharmony_ci int err) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct microread_info *info = context; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci switch (info->async_cb_type) { 3648c2ecf20Sopenharmony_ci case MICROREAD_CB_TYPE_READER_ALL: 3658c2ecf20Sopenharmony_ci if (err == 0) { 3668c2ecf20Sopenharmony_ci if (skb->len == 0) { 3678c2ecf20Sopenharmony_ci err = -EPROTO; 3688c2ecf20Sopenharmony_ci kfree_skb(skb); 3698c2ecf20Sopenharmony_ci info->async_cb(info->async_cb_context, NULL, 3708c2ecf20Sopenharmony_ci -EPROTO); 3718c2ecf20Sopenharmony_ci return; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (skb->data[skb->len - 1] != 0) { 3758c2ecf20Sopenharmony_ci err = nfc_hci_result_to_errno( 3768c2ecf20Sopenharmony_ci skb->data[skb->len - 1]); 3778c2ecf20Sopenharmony_ci kfree_skb(skb); 3788c2ecf20Sopenharmony_ci info->async_cb(info->async_cb_context, NULL, 3798c2ecf20Sopenharmony_ci err); 3808c2ecf20Sopenharmony_ci return; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - 1); /* RF Error ind. */ 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci info->async_cb(info->async_cb_context, skb, err); 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci default: 3888c2ecf20Sopenharmony_ci if (err == 0) 3898c2ecf20Sopenharmony_ci kfree_skb(skb); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* 3958c2ecf20Sopenharmony_ci * Returns: 3968c2ecf20Sopenharmony_ci * <= 0: driver handled the data exchange 3978c2ecf20Sopenharmony_ci * 1: driver doesn't especially handle, please do standard processing 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_cistatic int microread_im_transceive(struct nfc_hci_dev *hdev, 4008c2ecf20Sopenharmony_ci struct nfc_target *target, 4018c2ecf20Sopenharmony_ci struct sk_buff *skb, data_exchange_cb_t cb, 4028c2ecf20Sopenharmony_ci void *cb_context) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct microread_info *info = nfc_hci_get_clientdata(hdev); 4058c2ecf20Sopenharmony_ci u8 control_bits; 4068c2ecf20Sopenharmony_ci u16 crc; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) { 4118c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return nfc_hci_send_event(hdev, target->hci_reader_gate, 4148c2ecf20Sopenharmony_ci MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF, 4158c2ecf20Sopenharmony_ci skb->data, skb->len); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci switch (target->hci_reader_gate) { 4198c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_ISO_A: 4208c2ecf20Sopenharmony_ci control_bits = 0xCB; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_ISO_A_3: 4238c2ecf20Sopenharmony_ci control_bits = 0xCB; 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_ISO_B: 4268c2ecf20Sopenharmony_ci control_bits = 0xCB; 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_NFC_T1: 4298c2ecf20Sopenharmony_ci control_bits = 0x1B; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci crc = crc_ccitt(0xffff, skb->data, skb->len); 4328c2ecf20Sopenharmony_ci crc = ~crc; 4338c2ecf20Sopenharmony_ci skb_put_u8(skb, crc & 0xff); 4348c2ecf20Sopenharmony_ci skb_put_u8(skb, crc >> 8); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_NFC_T3: 4378c2ecf20Sopenharmony_ci control_bits = 0xDB; 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci default: 4408c2ecf20Sopenharmony_ci pr_info("Abort im_transceive to invalid gate 0x%x\n", 4418c2ecf20Sopenharmony_ci target->hci_reader_gate); 4428c2ecf20Sopenharmony_ci return 1; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = control_bits; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL; 4488c2ecf20Sopenharmony_ci info->async_cb = cb; 4498c2ecf20Sopenharmony_ci info->async_cb_context = cb_context; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, 4528c2ecf20Sopenharmony_ci MICROREAD_CMD_MREAD_EXCHANGE, 4538c2ecf20Sopenharmony_ci skb->data, skb->len, 4548c2ecf20Sopenharmony_ci microread_im_transceive_cb, info); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci int r; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET, 4628c2ecf20Sopenharmony_ci MICROREAD_EVT_MCARD_EXCHANGE, 4638c2ecf20Sopenharmony_ci skb->data, skb->len); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci kfree_skb(skb); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return r; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate, 4718c2ecf20Sopenharmony_ci struct sk_buff *skb) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct nfc_target *targets; 4748c2ecf20Sopenharmony_ci int r = 0; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci pr_info("target discovered to gate 0x%x\n", gate); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL); 4798c2ecf20Sopenharmony_ci if (targets == NULL) { 4808c2ecf20Sopenharmony_ci r = -ENOMEM; 4818c2ecf20Sopenharmony_ci goto exit; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci targets->hci_reader_gate = gate; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci switch (gate) { 4878c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_ISO_A: 4888c2ecf20Sopenharmony_ci targets->supported_protocols = 4898c2ecf20Sopenharmony_ci nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]); 4908c2ecf20Sopenharmony_ci targets->sens_res = 4918c2ecf20Sopenharmony_ci be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]); 4928c2ecf20Sopenharmony_ci targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK]; 4938c2ecf20Sopenharmony_ci targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN]; 4948c2ecf20Sopenharmony_ci if (targets->nfcid1_len > sizeof(targets->nfcid1)) { 4958c2ecf20Sopenharmony_ci r = -EINVAL; 4968c2ecf20Sopenharmony_ci goto exit_free; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID], 4998c2ecf20Sopenharmony_ci targets->nfcid1_len); 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_ISO_A_3: 5028c2ecf20Sopenharmony_ci targets->supported_protocols = 5038c2ecf20Sopenharmony_ci nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]); 5048c2ecf20Sopenharmony_ci targets->sens_res = 5058c2ecf20Sopenharmony_ci be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]); 5068c2ecf20Sopenharmony_ci targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK]; 5078c2ecf20Sopenharmony_ci targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN]; 5088c2ecf20Sopenharmony_ci if (targets->nfcid1_len > sizeof(targets->nfcid1)) { 5098c2ecf20Sopenharmony_ci r = -EINVAL; 5108c2ecf20Sopenharmony_ci goto exit_free; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID], 5138c2ecf20Sopenharmony_ci targets->nfcid1_len); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_ISO_B: 5168c2ecf20Sopenharmony_ci targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; 5178c2ecf20Sopenharmony_ci memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4); 5188c2ecf20Sopenharmony_ci targets->nfcid1_len = 4; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_NFC_T1: 5218c2ecf20Sopenharmony_ci targets->supported_protocols = NFC_PROTO_JEWEL_MASK; 5228c2ecf20Sopenharmony_ci targets->sens_res = 5238c2ecf20Sopenharmony_ci le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]); 5248c2ecf20Sopenharmony_ci memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4); 5258c2ecf20Sopenharmony_ci targets->nfcid1_len = 4; 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci case MICROREAD_GATE_ID_MREAD_NFC_T3: 5288c2ecf20Sopenharmony_ci targets->supported_protocols = NFC_PROTO_FELICA_MASK; 5298c2ecf20Sopenharmony_ci memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8); 5308c2ecf20Sopenharmony_ci targets->nfcid1_len = 8; 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci default: 5338c2ecf20Sopenharmony_ci pr_info("discard target discovered to gate 0x%x\n", gate); 5348c2ecf20Sopenharmony_ci goto exit_free; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci r = nfc_targets_found(hdev->ndev, targets, 1); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ciexit_free: 5408c2ecf20Sopenharmony_ci kfree(targets); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciexit: 5438c2ecf20Sopenharmony_ci kfree_skb(skb); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (r) 5468c2ecf20Sopenharmony_ci pr_err("Failed to handle discovered target err=%d\n", r); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic int microread_event_received(struct nfc_hci_dev *hdev, u8 pipe, 5508c2ecf20Sopenharmony_ci u8 event, struct sk_buff *skb) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci int r; 5538c2ecf20Sopenharmony_ci u8 gate = hdev->pipes[pipe].gate; 5548c2ecf20Sopenharmony_ci u8 mode; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci switch (event) { 5598c2ecf20Sopenharmony_ci case MICROREAD_EVT_MREAD_CARD_FOUND: 5608c2ecf20Sopenharmony_ci microread_target_discovered(hdev, gate, skb); 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF: 5648c2ecf20Sopenharmony_ci if (skb->len < 1) { 5658c2ecf20Sopenharmony_ci kfree_skb(skb); 5668c2ecf20Sopenharmony_ci return -EPROTO; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (skb->data[skb->len - 1]) { 5708c2ecf20Sopenharmony_ci kfree_skb(skb); 5718c2ecf20Sopenharmony_ci return -EIO; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - 1); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci r = nfc_tm_data_received(hdev->ndev, skb); 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci case MICROREAD_EVT_MCARD_FIELD_ON: 5808c2ecf20Sopenharmony_ci case MICROREAD_EVT_MCARD_FIELD_OFF: 5818c2ecf20Sopenharmony_ci kfree_skb(skb); 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci case MICROREAD_EVT_P2P_TARGET_ACTIVATED: 5858c2ecf20Sopenharmony_ci r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, 5868c2ecf20Sopenharmony_ci NFC_COMM_PASSIVE, skb->data, 5878c2ecf20Sopenharmony_ci skb->len); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci kfree_skb(skb); 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci case MICROREAD_EVT_MCARD_EXCHANGE: 5938c2ecf20Sopenharmony_ci if (skb->len < 1) { 5948c2ecf20Sopenharmony_ci kfree_skb(skb); 5958c2ecf20Sopenharmony_ci return -EPROTO; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (skb->data[skb->len-1]) { 5998c2ecf20Sopenharmony_ci kfree_skb(skb); 6008c2ecf20Sopenharmony_ci return -EIO; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - 1); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci r = nfc_tm_data_received(hdev->ndev, skb); 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci case MICROREAD_EVT_P2P_TARGET_DEACTIVATED: 6098c2ecf20Sopenharmony_ci kfree_skb(skb); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci mode = 0xff; 6128c2ecf20Sopenharmony_ci r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, 6138c2ecf20Sopenharmony_ci MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); 6148c2ecf20Sopenharmony_ci if (r) 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci r = nfc_hci_send_event(hdev, gate, 6188c2ecf20Sopenharmony_ci MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 6198c2ecf20Sopenharmony_ci 0); 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci default: 6238c2ecf20Sopenharmony_ci return 1; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return r; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic struct nfc_hci_ops microread_hci_ops = { 6308c2ecf20Sopenharmony_ci .open = microread_open, 6318c2ecf20Sopenharmony_ci .close = microread_close, 6328c2ecf20Sopenharmony_ci .hci_ready = microread_hci_ready, 6338c2ecf20Sopenharmony_ci .xmit = microread_xmit, 6348c2ecf20Sopenharmony_ci .start_poll = microread_start_poll, 6358c2ecf20Sopenharmony_ci .dep_link_up = microread_dep_link_up, 6368c2ecf20Sopenharmony_ci .dep_link_down = microread_dep_link_down, 6378c2ecf20Sopenharmony_ci .target_from_gate = microread_target_from_gate, 6388c2ecf20Sopenharmony_ci .complete_target_discovered = microread_complete_target_discovered, 6398c2ecf20Sopenharmony_ci .im_transceive = microread_im_transceive, 6408c2ecf20Sopenharmony_ci .tm_send = microread_tm_send, 6418c2ecf20Sopenharmony_ci .check_presence = NULL, 6428c2ecf20Sopenharmony_ci .event_received = microread_event_received, 6438c2ecf20Sopenharmony_ci}; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ciint microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, 6468c2ecf20Sopenharmony_ci int phy_headroom, int phy_tailroom, int phy_payload, 6478c2ecf20Sopenharmony_ci struct nfc_hci_dev **hdev) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct microread_info *info; 6508c2ecf20Sopenharmony_ci unsigned long quirks = 0; 6518c2ecf20Sopenharmony_ci u32 protocols; 6528c2ecf20Sopenharmony_ci struct nfc_hci_init_data init_data; 6538c2ecf20Sopenharmony_ci int r; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci info = kzalloc(sizeof(struct microread_info), GFP_KERNEL); 6568c2ecf20Sopenharmony_ci if (!info) { 6578c2ecf20Sopenharmony_ci r = -ENOMEM; 6588c2ecf20Sopenharmony_ci goto err_info_alloc; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci info->phy_ops = phy_ops; 6628c2ecf20Sopenharmony_ci info->phy_id = phy_id; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci init_data.gate_count = ARRAY_SIZE(microread_gates); 6658c2ecf20Sopenharmony_ci memcpy(init_data.gates, microread_gates, sizeof(microread_gates)); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci strcpy(init_data.session_id, "MICROREA"); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci protocols = NFC_PROTO_JEWEL_MASK | 6728c2ecf20Sopenharmony_ci NFC_PROTO_MIFARE_MASK | 6738c2ecf20Sopenharmony_ci NFC_PROTO_FELICA_MASK | 6748c2ecf20Sopenharmony_ci NFC_PROTO_ISO14443_MASK | 6758c2ecf20Sopenharmony_ci NFC_PROTO_ISO14443_B_MASK | 6768c2ecf20Sopenharmony_ci NFC_PROTO_NFC_DEP_MASK; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci info->hdev = nfc_hci_allocate_device(µread_hci_ops, &init_data, 6798c2ecf20Sopenharmony_ci quirks, protocols, llc_name, 6808c2ecf20Sopenharmony_ci phy_headroom + 6818c2ecf20Sopenharmony_ci MICROREAD_CMDS_HEADROOM, 6828c2ecf20Sopenharmony_ci phy_tailroom + 6838c2ecf20Sopenharmony_ci MICROREAD_CMD_TAILROOM, 6848c2ecf20Sopenharmony_ci phy_payload); 6858c2ecf20Sopenharmony_ci if (!info->hdev) { 6868c2ecf20Sopenharmony_ci pr_err("Cannot allocate nfc hdev\n"); 6878c2ecf20Sopenharmony_ci r = -ENOMEM; 6888c2ecf20Sopenharmony_ci goto err_alloc_hdev; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci nfc_hci_set_clientdata(info->hdev, info); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci r = nfc_hci_register_device(info->hdev); 6948c2ecf20Sopenharmony_ci if (r) 6958c2ecf20Sopenharmony_ci goto err_regdev; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci *hdev = info->hdev; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return 0; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cierr_regdev: 7028c2ecf20Sopenharmony_ci nfc_hci_free_device(info->hdev); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cierr_alloc_hdev: 7058c2ecf20Sopenharmony_ci kfree(info); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cierr_info_alloc: 7088c2ecf20Sopenharmony_ci return r; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(microread_probe); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_civoid microread_remove(struct nfc_hci_dev *hdev) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct microread_info *info = nfc_hci_get_clientdata(hdev); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci nfc_hci_unregister_device(hdev); 7178c2ecf20Sopenharmony_ci nfc_hci_free_device(hdev); 7188c2ecf20Sopenharmony_ci kfree(info); 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(microread_remove); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 724