11c54795dSChristophe Ricard /* 21c54795dSChristophe Ricard * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. 31c54795dSChristophe Ricard * 41c54795dSChristophe Ricard * This program is free software; you can redistribute it and/or modify it 51c54795dSChristophe Ricard * under the terms and conditions of the GNU General Public License, 61c54795dSChristophe Ricard * version 2, as published by the Free Software Foundation. 71c54795dSChristophe Ricard * 81c54795dSChristophe Ricard * This program is distributed in the hope that it will be useful, 91c54795dSChristophe Ricard * but WITHOUT ANY WARRANTY; without even the implied warranty of 101c54795dSChristophe Ricard * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 111c54795dSChristophe Ricard * GNU General Public License for more details. 121c54795dSChristophe Ricard * 131c54795dSChristophe Ricard * You should have received a copy of the GNU General Public License 141c54795dSChristophe Ricard * along with this program; if not, see <http://www.gnu.org/licenses/>. 151c54795dSChristophe Ricard */ 161c54795dSChristophe Ricard 171c54795dSChristophe Ricard #include <net/nfc/hci.h> 181c54795dSChristophe Ricard 191c54795dSChristophe Ricard #include "st21nfca.h" 201c54795dSChristophe Ricard 211c54795dSChristophe Ricard #define ST21NFCA_EVT_UICC_ACTIVATE 0x10 221c54795dSChristophe Ricard #define ST21NFCA_EVT_UICC_DEACTIVATE 0x13 231c54795dSChristophe Ricard #define ST21NFCA_EVT_SE_HARD_RESET 0x20 241c54795dSChristophe Ricard #define ST21NFCA_EVT_SE_SOFT_RESET 0x11 251c54795dSChristophe Ricard #define ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER 0x21 261c54795dSChristophe Ricard #define ST21NFCA_EVT_SE_ACTIVATE 0x22 271c54795dSChristophe Ricard #define ST21NFCA_EVT_SE_DEACTIVATE 0x23 281c54795dSChristophe Ricard 291c54795dSChristophe Ricard #define ST21NFCA_EVT_TRANSMIT_DATA 0x10 301c54795dSChristophe Ricard #define ST21NFCA_EVT_WTX_REQUEST 0x11 311c54795dSChristophe Ricard 321c54795dSChristophe Ricard #define ST21NFCA_EVT_CONNECTIVITY 0x10 331c54795dSChristophe Ricard #define ST21NFCA_EVT_TRANSACTION 0x12 341c54795dSChristophe Ricard 351c54795dSChristophe Ricard #define ST21NFCA_ESE_HOST_ID 0xc0 361c54795dSChristophe Ricard 371c54795dSChristophe Ricard #define ST21NFCA_SE_TO_HOT_PLUG 1000 381c54795dSChristophe Ricard /* Connectivity pipe only */ 391c54795dSChristophe Ricard #define ST21NFCA_SE_COUNT_PIPE_UICC 0x01 401c54795dSChristophe Ricard /* Connectivity + APDU Reader pipe */ 411c54795dSChristophe Ricard #define ST21NFCA_SE_COUNT_PIPE_EMBEDDED 0x02 421c54795dSChristophe Ricard 431c54795dSChristophe Ricard #define ST21NFCA_SE_MODE_OFF 0x00 441c54795dSChristophe Ricard #define ST21NFCA_SE_MODE_ON 0x01 451c54795dSChristophe Ricard 461c54795dSChristophe Ricard #define ST21NFCA_PARAM_ATR 0x01 471c54795dSChristophe Ricard #define ST21NFCA_ATR_DEFAULT_BWI 0x04 481c54795dSChristophe Ricard 491c54795dSChristophe Ricard /* 501c54795dSChristophe Ricard * WT = 2^BWI/10[s], convert into msecs and add a secure 511c54795dSChristophe Ricard * room by increasing by 2 this timeout 521c54795dSChristophe Ricard */ 531c54795dSChristophe Ricard #define ST21NFCA_BWI_TO_TIMEOUT(x) ((1 << x) * 200) 541c54795dSChristophe Ricard #define ST21NFCA_ATR_GET_Y_FROM_TD(x) (x >> 4) 551c54795dSChristophe Ricard 561c54795dSChristophe Ricard /* If TA is present bit 0 is set */ 571c54795dSChristophe Ricard #define ST21NFCA_ATR_TA_PRESENT(x) (x & 0x01) 581c54795dSChristophe Ricard /* If TB is present bit 1 is set */ 591c54795dSChristophe Ricard #define ST21NFCA_ATR_TB_PRESENT(x) (x & 0x02) 601c54795dSChristophe Ricard 611c54795dSChristophe Ricard static u8 st21nfca_se_get_bwi(struct nfc_hci_dev *hdev) 621c54795dSChristophe Ricard { 631c54795dSChristophe Ricard int i; 641c54795dSChristophe Ricard u8 td; 651c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 661c54795dSChristophe Ricard 671c54795dSChristophe Ricard /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */ 681c54795dSChristophe Ricard for (i = 1; i < ST21NFCA_ESE_MAX_LENGTH; i++) { 691c54795dSChristophe Ricard td = ST21NFCA_ATR_GET_Y_FROM_TD(info->se_info.atr[i]); 701c54795dSChristophe Ricard if (ST21NFCA_ATR_TA_PRESENT(td)) 711c54795dSChristophe Ricard i++; 721c54795dSChristophe Ricard if (ST21NFCA_ATR_TB_PRESENT(td)) { 731c54795dSChristophe Ricard i++; 741c54795dSChristophe Ricard return info->se_info.atr[i] >> 4; 751c54795dSChristophe Ricard } 761c54795dSChristophe Ricard } 771c54795dSChristophe Ricard return ST21NFCA_ATR_DEFAULT_BWI; 781c54795dSChristophe Ricard } 791c54795dSChristophe Ricard 801c54795dSChristophe Ricard static void st21nfca_se_get_atr(struct nfc_hci_dev *hdev) 811c54795dSChristophe Ricard { 821c54795dSChristophe Ricard int r; 831c54795dSChristophe Ricard struct sk_buff *skb; 841c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 851c54795dSChristophe Ricard 861c54795dSChristophe Ricard r = nfc_hci_get_param(hdev, ST21NFCA_APDU_READER_GATE, 871c54795dSChristophe Ricard ST21NFCA_PARAM_ATR, &skb); 881c54795dSChristophe Ricard if (r < 0) 891c54795dSChristophe Ricard return; 901c54795dSChristophe Ricard 911c54795dSChristophe Ricard if (skb->len <= ST21NFCA_ESE_MAX_LENGTH) { 921c54795dSChristophe Ricard memcpy(info->se_info.atr, skb->data, skb->len); 931c54795dSChristophe Ricard info->se_info.wt_timeout = 941c54795dSChristophe Ricard ST21NFCA_BWI_TO_TIMEOUT(st21nfca_se_get_bwi(hdev)); 951c54795dSChristophe Ricard } 961c54795dSChristophe Ricard kfree_skb(skb); 971c54795dSChristophe Ricard } 981c54795dSChristophe Ricard 991c54795dSChristophe Ricard static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx, 1001c54795dSChristophe Ricard u8 state) 1011c54795dSChristophe Ricard { 1021c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 103cde2aa99SChristophe Ricard int r, i; 1041c54795dSChristophe Ricard struct sk_buff *sk_host_list; 1051c54795dSChristophe Ricard u8 se_event, host_id; 1061c54795dSChristophe Ricard 1071c54795dSChristophe Ricard switch (se_idx) { 1081c54795dSChristophe Ricard case NFC_HCI_UICC_HOST_ID: 1091c54795dSChristophe Ricard se_event = (state == ST21NFCA_SE_MODE_ON ? 1101c54795dSChristophe Ricard ST21NFCA_EVT_UICC_ACTIVATE : 1111c54795dSChristophe Ricard ST21NFCA_EVT_UICC_DEACTIVATE); 1121c54795dSChristophe Ricard 1131c54795dSChristophe Ricard info->se_info.count_pipes = 0; 1141c54795dSChristophe Ricard info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_UICC; 1151c54795dSChristophe Ricard break; 1161c54795dSChristophe Ricard case ST21NFCA_ESE_HOST_ID: 1171c54795dSChristophe Ricard se_event = (state == ST21NFCA_SE_MODE_ON ? 1181c54795dSChristophe Ricard ST21NFCA_EVT_SE_ACTIVATE : 1191c54795dSChristophe Ricard ST21NFCA_EVT_SE_DEACTIVATE); 1201c54795dSChristophe Ricard 1211c54795dSChristophe Ricard info->se_info.count_pipes = 0; 1221c54795dSChristophe Ricard info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_EMBEDDED; 1231c54795dSChristophe Ricard break; 1241c54795dSChristophe Ricard default: 1251c54795dSChristophe Ricard return -EINVAL; 1261c54795dSChristophe Ricard } 1271c54795dSChristophe Ricard 1281c54795dSChristophe Ricard /* 1291c54795dSChristophe Ricard * Wait for an EVT_HOT_PLUG in order to 1301c54795dSChristophe Ricard * retrieve a relevant host list. 1311c54795dSChristophe Ricard */ 1321c54795dSChristophe Ricard reinit_completion(&info->se_info.req_completion); 1331c54795dSChristophe Ricard r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, se_event, 1341c54795dSChristophe Ricard NULL, 0); 1351c54795dSChristophe Ricard if (r < 0) 1361c54795dSChristophe Ricard return r; 1371c54795dSChristophe Ricard 1381c54795dSChristophe Ricard mod_timer(&info->se_info.se_active_timer, jiffies + 1391c54795dSChristophe Ricard msecs_to_jiffies(ST21NFCA_SE_TO_HOT_PLUG)); 1401c54795dSChristophe Ricard info->se_info.se_active = true; 1411c54795dSChristophe Ricard 1421c54795dSChristophe Ricard /* Ignore return value and check in any case the host_list */ 1431c54795dSChristophe Ricard wait_for_completion_interruptible(&info->se_info.req_completion); 1441c54795dSChristophe Ricard 1451c54795dSChristophe Ricard r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE, 1461c54795dSChristophe Ricard NFC_HCI_ADMIN_HOST_LIST, 1471c54795dSChristophe Ricard &sk_host_list); 1481c54795dSChristophe Ricard if (r < 0) 1491c54795dSChristophe Ricard return r; 1501c54795dSChristophe Ricard 151cde2aa99SChristophe Ricard for (i = 0; i < sk_host_list->len && 152cde2aa99SChristophe Ricard sk_host_list->data[i] != se_idx; i++) 153cde2aa99SChristophe Ricard ; 154cde2aa99SChristophe Ricard host_id = sk_host_list->data[i]; 1551c54795dSChristophe Ricard kfree_skb(sk_host_list); 1561c54795dSChristophe Ricard 1571c54795dSChristophe Ricard if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx) 1581c54795dSChristophe Ricard return se_idx; 1591c54795dSChristophe Ricard else if (state == ST21NFCA_SE_MODE_OFF && host_id != se_idx) 1601c54795dSChristophe Ricard return se_idx; 1611c54795dSChristophe Ricard 1621c54795dSChristophe Ricard return -1; 1631c54795dSChristophe Ricard } 1641c54795dSChristophe Ricard 1651c54795dSChristophe Ricard int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev) 1661c54795dSChristophe Ricard { 1671c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 1681c54795dSChristophe Ricard int se_count = 0; 1691c54795dSChristophe Ricard 1701c54795dSChristophe Ricard if (info->se_status->is_uicc_present) { 1711c54795dSChristophe Ricard nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC); 1721c54795dSChristophe Ricard se_count++; 1731c54795dSChristophe Ricard } 1741c54795dSChristophe Ricard 1751c54795dSChristophe Ricard if (info->se_status->is_ese_present) { 1761c54795dSChristophe Ricard nfc_add_se(hdev->ndev, ST21NFCA_ESE_HOST_ID, NFC_SE_EMBEDDED); 1771c54795dSChristophe Ricard se_count++; 1781c54795dSChristophe Ricard } 1791c54795dSChristophe Ricard 1801c54795dSChristophe Ricard return !se_count; 1811c54795dSChristophe Ricard } 1821c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_hci_discover_se); 1831c54795dSChristophe Ricard 1841c54795dSChristophe Ricard int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx) 1851c54795dSChristophe Ricard { 1861c54795dSChristophe Ricard int r; 1871c54795dSChristophe Ricard 1881c54795dSChristophe Ricard /* 1891c54795dSChristophe Ricard * According to upper layer, se_idx == NFC_SE_UICC when 1901c54795dSChristophe Ricard * info->se_status->is_uicc_enable is true should never happen. 1911c54795dSChristophe Ricard * Same for eSE. 1921c54795dSChristophe Ricard */ 1931c54795dSChristophe Ricard r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON); 1941c54795dSChristophe Ricard 1951c54795dSChristophe Ricard if (r == ST21NFCA_ESE_HOST_ID) { 1961c54795dSChristophe Ricard st21nfca_se_get_atr(hdev); 1971c54795dSChristophe Ricard r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE, 1981c54795dSChristophe Ricard ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0); 1991c54795dSChristophe Ricard if (r < 0) 2001c54795dSChristophe Ricard return r; 2011c54795dSChristophe Ricard } else if (r < 0) { 2021c54795dSChristophe Ricard /* 2031c54795dSChristophe Ricard * The activation tentative failed, the secure element 2041c54795dSChristophe Ricard * is not connected. Remove from the list. 2051c54795dSChristophe Ricard */ 2061c54795dSChristophe Ricard nfc_remove_se(hdev->ndev, se_idx); 2071c54795dSChristophe Ricard return r; 2081c54795dSChristophe Ricard } 2091c54795dSChristophe Ricard 2101c54795dSChristophe Ricard return 0; 2111c54795dSChristophe Ricard } 2121c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_hci_enable_se); 2131c54795dSChristophe Ricard 2141c54795dSChristophe Ricard int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx) 2151c54795dSChristophe Ricard { 2161c54795dSChristophe Ricard int r; 2171c54795dSChristophe Ricard 2181c54795dSChristophe Ricard /* 2191c54795dSChristophe Ricard * According to upper layer, se_idx == NFC_SE_UICC when 2201c54795dSChristophe Ricard * info->se_status->is_uicc_enable is true should never happen 2211c54795dSChristophe Ricard * Same for eSE. 2221c54795dSChristophe Ricard */ 2231c54795dSChristophe Ricard r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_OFF); 2241c54795dSChristophe Ricard if (r < 0) 2251c54795dSChristophe Ricard return r; 2261c54795dSChristophe Ricard 2271c54795dSChristophe Ricard return 0; 2281c54795dSChristophe Ricard } 2291c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_hci_disable_se); 2301c54795dSChristophe Ricard 2311c54795dSChristophe Ricard int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx, 2321c54795dSChristophe Ricard u8 *apdu, size_t apdu_length, 2331c54795dSChristophe Ricard se_io_cb_t cb, void *cb_context) 2341c54795dSChristophe Ricard { 2351c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 2361c54795dSChristophe Ricard 2371c54795dSChristophe Ricard pr_debug("se_io %x\n", se_idx); 2381c54795dSChristophe Ricard 2391c54795dSChristophe Ricard switch (se_idx) { 2401c54795dSChristophe Ricard case ST21NFCA_ESE_HOST_ID: 2411c54795dSChristophe Ricard info->se_info.cb = cb; 2421c54795dSChristophe Ricard info->se_info.cb_context = cb_context; 2431c54795dSChristophe Ricard mod_timer(&info->se_info.bwi_timer, jiffies + 2441c54795dSChristophe Ricard msecs_to_jiffies(info->se_info.wt_timeout)); 2451c54795dSChristophe Ricard info->se_info.bwi_active = true; 2461c54795dSChristophe Ricard return nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE, 2471c54795dSChristophe Ricard ST21NFCA_EVT_TRANSMIT_DATA, 2481c54795dSChristophe Ricard apdu, apdu_length); 2491c54795dSChristophe Ricard default: 2501c54795dSChristophe Ricard return -ENODEV; 2511c54795dSChristophe Ricard } 2521c54795dSChristophe Ricard } 2531c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_hci_se_io); 2541c54795dSChristophe Ricard 2551c54795dSChristophe Ricard static void st21nfca_se_wt_timeout(unsigned long data) 2561c54795dSChristophe Ricard { 2571c54795dSChristophe Ricard /* 2581c54795dSChristophe Ricard * No answer from the secure element 2591c54795dSChristophe Ricard * within the defined timeout. 2601c54795dSChristophe Ricard * Let's send a reset request as recovery procedure. 2611c54795dSChristophe Ricard * According to the situation, we first try to send a software reset 2621c54795dSChristophe Ricard * to the secure element. If the next command is still not 2631c54795dSChristophe Ricard * answering in time, we send to the CLF a secure element hardware 2641c54795dSChristophe Ricard * reset request. 2651c54795dSChristophe Ricard */ 2661c54795dSChristophe Ricard /* hardware reset managed through VCC_UICC_OUT power supply */ 2671c54795dSChristophe Ricard u8 param = 0x01; 2681c54795dSChristophe Ricard struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data; 2691c54795dSChristophe Ricard 2701c54795dSChristophe Ricard pr_debug("\n"); 2711c54795dSChristophe Ricard 2721c54795dSChristophe Ricard info->se_info.bwi_active = false; 2731c54795dSChristophe Ricard 2741c54795dSChristophe Ricard if (!info->se_info.xch_error) { 2751c54795dSChristophe Ricard info->se_info.xch_error = true; 2761c54795dSChristophe Ricard nfc_hci_send_event(info->hdev, ST21NFCA_APDU_READER_GATE, 2771c54795dSChristophe Ricard ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0); 2781c54795dSChristophe Ricard } else { 2791c54795dSChristophe Ricard info->se_info.xch_error = false; 2801c54795dSChristophe Ricard nfc_hci_send_event(info->hdev, ST21NFCA_DEVICE_MGNT_GATE, 2811c54795dSChristophe Ricard ST21NFCA_EVT_SE_HARD_RESET, ¶m, 1); 2821c54795dSChristophe Ricard } 2831c54795dSChristophe Ricard info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME); 2841c54795dSChristophe Ricard } 2851c54795dSChristophe Ricard 2861c54795dSChristophe Ricard static void st21nfca_se_activation_timeout(unsigned long data) 2871c54795dSChristophe Ricard { 2881c54795dSChristophe Ricard struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data; 2891c54795dSChristophe Ricard 2901c54795dSChristophe Ricard pr_debug("\n"); 2911c54795dSChristophe Ricard 2921c54795dSChristophe Ricard info->se_info.se_active = false; 2931c54795dSChristophe Ricard 2941c54795dSChristophe Ricard complete(&info->se_info.req_completion); 2951c54795dSChristophe Ricard } 2961c54795dSChristophe Ricard 2971c54795dSChristophe Ricard /* 2981c54795dSChristophe Ricard * Returns: 2991c54795dSChristophe Ricard * <= 0: driver handled the event, skb consumed 3001c54795dSChristophe Ricard * 1: driver does not handle the event, please do standard processing 3011c54795dSChristophe Ricard */ 3021c54795dSChristophe Ricard int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, 3031c54795dSChristophe Ricard u8 event, struct sk_buff *skb) 3041c54795dSChristophe Ricard { 3051c54795dSChristophe Ricard int r = 0; 3061c54795dSChristophe Ricard struct device *dev = &hdev->ndev->dev; 3071c54795dSChristophe Ricard struct nfc_evt_transaction *transaction; 3081c54795dSChristophe Ricard 3091c54795dSChristophe Ricard pr_debug("connectivity gate event: %x\n", event); 3101c54795dSChristophe Ricard 3111c54795dSChristophe Ricard switch (event) { 3121c54795dSChristophe Ricard case ST21NFCA_EVT_CONNECTIVITY: 3131c54795dSChristophe Ricard break; 3141c54795dSChristophe Ricard case ST21NFCA_EVT_TRANSACTION: 3151c54795dSChristophe Ricard /* 3161c54795dSChristophe Ricard * According to specification etsi 102 622 3171c54795dSChristophe Ricard * 11.2.2.4 EVT_TRANSACTION Table 52 3181c54795dSChristophe Ricard * Description Tag Length 3191c54795dSChristophe Ricard * AID 81 5 to 16 3201c54795dSChristophe Ricard * PARAMETERS 82 0 to 255 3211c54795dSChristophe Ricard */ 3221c54795dSChristophe Ricard if (skb->len < NFC_MIN_AID_LENGTH + 2 && 3231c54795dSChristophe Ricard skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) 3241c54795dSChristophe Ricard return -EPROTO; 3251c54795dSChristophe Ricard 3261c54795dSChristophe Ricard transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev, 3271c54795dSChristophe Ricard skb->len - 2, GFP_KERNEL); 3281c54795dSChristophe Ricard 3291c54795dSChristophe Ricard transaction->aid_len = skb->data[1]; 3301c54795dSChristophe Ricard memcpy(transaction->aid, &skb->data[2], 3311c54795dSChristophe Ricard transaction->aid_len); 3321c54795dSChristophe Ricard 3331c54795dSChristophe Ricard /* Check next byte is PARAMETERS tag (82) */ 3341c54795dSChristophe Ricard if (skb->data[transaction->aid_len + 2] != 3351c54795dSChristophe Ricard NFC_EVT_TRANSACTION_PARAMS_TAG) 3361c54795dSChristophe Ricard return -EPROTO; 3371c54795dSChristophe Ricard 3381c54795dSChristophe Ricard transaction->params_len = skb->data[transaction->aid_len + 3]; 3391c54795dSChristophe Ricard memcpy(transaction->params, skb->data + 3401c54795dSChristophe Ricard transaction->aid_len + 4, transaction->params_len); 3411c54795dSChristophe Ricard 3421c54795dSChristophe Ricard r = nfc_se_transaction(hdev->ndev, host, transaction); 3431c54795dSChristophe Ricard break; 3441c54795dSChristophe Ricard default: 3451c54795dSChristophe Ricard return 1; 3461c54795dSChristophe Ricard } 3471c54795dSChristophe Ricard kfree_skb(skb); 3481c54795dSChristophe Ricard return r; 3491c54795dSChristophe Ricard } 3501c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_connectivity_event_received); 3511c54795dSChristophe Ricard 3521c54795dSChristophe Ricard int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev, 3531c54795dSChristophe Ricard u8 event, struct sk_buff *skb) 3541c54795dSChristophe Ricard { 3551c54795dSChristophe Ricard int r = 0; 3561c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 3571c54795dSChristophe Ricard 3581c54795dSChristophe Ricard pr_debug("apdu reader gate event: %x\n", event); 3591c54795dSChristophe Ricard 3601c54795dSChristophe Ricard switch (event) { 3611c54795dSChristophe Ricard case ST21NFCA_EVT_TRANSMIT_DATA: 3621c54795dSChristophe Ricard del_timer_sync(&info->se_info.bwi_timer); 3631c54795dSChristophe Ricard info->se_info.bwi_active = false; 3641c54795dSChristophe Ricard r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, 3651c54795dSChristophe Ricard ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); 3661c54795dSChristophe Ricard if (r < 0) 3671c54795dSChristophe Ricard goto exit; 3681c54795dSChristophe Ricard 3691c54795dSChristophe Ricard info->se_info.cb(info->se_info.cb_context, 3701c54795dSChristophe Ricard skb->data, skb->len, 0); 3711c54795dSChristophe Ricard break; 3721c54795dSChristophe Ricard case ST21NFCA_EVT_WTX_REQUEST: 3731c54795dSChristophe Ricard mod_timer(&info->se_info.bwi_timer, jiffies + 3741c54795dSChristophe Ricard msecs_to_jiffies(info->se_info.wt_timeout)); 3751c54795dSChristophe Ricard break; 3761c54795dSChristophe Ricard } 3771c54795dSChristophe Ricard 3781c54795dSChristophe Ricard exit: 3791c54795dSChristophe Ricard kfree_skb(skb); 3801c54795dSChristophe Ricard return r; 3811c54795dSChristophe Ricard } 3821c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_apdu_reader_event_received); 3831c54795dSChristophe Ricard 3841c54795dSChristophe Ricard void st21nfca_se_init(struct nfc_hci_dev *hdev) 3851c54795dSChristophe Ricard { 3861c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 3871c54795dSChristophe Ricard 3881c54795dSChristophe Ricard init_completion(&info->se_info.req_completion); 3891c54795dSChristophe Ricard /* initialize timers */ 3901c54795dSChristophe Ricard init_timer(&info->se_info.bwi_timer); 3911c54795dSChristophe Ricard info->se_info.bwi_timer.data = (unsigned long)info; 3921c54795dSChristophe Ricard info->se_info.bwi_timer.function = st21nfca_se_wt_timeout; 3931c54795dSChristophe Ricard info->se_info.bwi_active = false; 3941c54795dSChristophe Ricard 3951c54795dSChristophe Ricard init_timer(&info->se_info.se_active_timer); 3961c54795dSChristophe Ricard info->se_info.se_active_timer.data = (unsigned long)info; 3971c54795dSChristophe Ricard info->se_info.se_active_timer.function = st21nfca_se_activation_timeout; 3981c54795dSChristophe Ricard info->se_info.se_active = false; 3991c54795dSChristophe Ricard 4001c54795dSChristophe Ricard info->se_info.count_pipes = 0; 4011c54795dSChristophe Ricard info->se_info.expected_pipes = 0; 4021c54795dSChristophe Ricard 4031c54795dSChristophe Ricard info->se_info.xch_error = false; 4041c54795dSChristophe Ricard 4051c54795dSChristophe Ricard info->se_info.wt_timeout = 4061c54795dSChristophe Ricard ST21NFCA_BWI_TO_TIMEOUT(ST21NFCA_ATR_DEFAULT_BWI); 4071c54795dSChristophe Ricard } 4081c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_se_init); 4091c54795dSChristophe Ricard 4101c54795dSChristophe Ricard void st21nfca_se_deinit(struct nfc_hci_dev *hdev) 4111c54795dSChristophe Ricard { 4121c54795dSChristophe Ricard struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 4131c54795dSChristophe Ricard 4141c54795dSChristophe Ricard if (info->se_info.bwi_active) 4151c54795dSChristophe Ricard del_timer_sync(&info->se_info.bwi_timer); 4161c54795dSChristophe Ricard if (info->se_info.se_active) 4171c54795dSChristophe Ricard del_timer_sync(&info->se_info.se_active_timer); 4181c54795dSChristophe Ricard 4191c54795dSChristophe Ricard info->se_info.bwi_active = false; 4201c54795dSChristophe Ricard info->se_info.se_active = false; 4211c54795dSChristophe Ricard } 4221c54795dSChristophe Ricard EXPORT_SYMBOL(st21nfca_se_deinit); 423