162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Intel Corporation. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) "hci: %s: " fmt, __func__ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/nfc.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <net/nfc/nfc.h> 1462306a36Sopenharmony_ci#include <net/nfc/hci.h> 1562306a36Sopenharmony_ci#include <net/nfc/llc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "hci.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Largest headroom needed for outgoing HCI commands */ 2062306a36Sopenharmony_ci#define HCI_CMDS_HEADROOM 1 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciint nfc_hci_result_to_errno(u8 result) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci switch (result) { 2562306a36Sopenharmony_ci case NFC_HCI_ANY_OK: 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci case NFC_HCI_ANY_E_REG_PAR_UNKNOWN: 2862306a36Sopenharmony_ci return -EOPNOTSUPP; 2962306a36Sopenharmony_ci case NFC_HCI_ANY_E_TIMEOUT: 3062306a36Sopenharmony_ci return -ETIME; 3162306a36Sopenharmony_ci default: 3262306a36Sopenharmony_ci return -1; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_result_to_errno); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid nfc_hci_reset_pipes(struct nfc_hci_dev *hdev) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int i = 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci for (i = 0; i < NFC_HCI_MAX_PIPES; i++) { 4262306a36Sopenharmony_ci hdev->pipes[i].gate = NFC_HCI_INVALID_GATE; 4362306a36Sopenharmony_ci hdev->pipes[i].dest_host = NFC_HCI_INVALID_HOST; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe)); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_reset_pipes); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_civoid nfc_hci_reset_pipes_per_host(struct nfc_hci_dev *hdev, u8 host) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci int i = 0; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci for (i = 0; i < NFC_HCI_MAX_PIPES; i++) { 5462306a36Sopenharmony_ci if (hdev->pipes[i].dest_host != host) 5562306a36Sopenharmony_ci continue; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci hdev->pipes[i].gate = NFC_HCI_INVALID_GATE; 5862306a36Sopenharmony_ci hdev->pipes[i].dest_host = NFC_HCI_INVALID_HOST; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_reset_pipes_per_host); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void nfc_hci_msg_tx_work(struct work_struct *work) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, 6662306a36Sopenharmony_ci msg_tx_work); 6762306a36Sopenharmony_ci struct hci_msg *msg; 6862306a36Sopenharmony_ci struct sk_buff *skb; 6962306a36Sopenharmony_ci int r = 0; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci mutex_lock(&hdev->msg_tx_mutex); 7262306a36Sopenharmony_ci if (hdev->shutting_down) 7362306a36Sopenharmony_ci goto exit; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (hdev->cmd_pending_msg) { 7662306a36Sopenharmony_ci if (timer_pending(&hdev->cmd_timer) == 0) { 7762306a36Sopenharmony_ci if (hdev->cmd_pending_msg->cb) 7862306a36Sopenharmony_ci hdev->cmd_pending_msg->cb(hdev-> 7962306a36Sopenharmony_ci cmd_pending_msg-> 8062306a36Sopenharmony_ci cb_context, 8162306a36Sopenharmony_ci NULL, 8262306a36Sopenharmony_ci -ETIME); 8362306a36Sopenharmony_ci kfree(hdev->cmd_pending_msg); 8462306a36Sopenharmony_ci hdev->cmd_pending_msg = NULL; 8562306a36Sopenharmony_ci } else { 8662306a36Sopenharmony_ci goto exit; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cinext_msg: 9162306a36Sopenharmony_ci if (list_empty(&hdev->msg_tx_queue)) 9262306a36Sopenharmony_ci goto exit; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci msg = list_first_entry(&hdev->msg_tx_queue, struct hci_msg, msg_l); 9562306a36Sopenharmony_ci list_del(&msg->msg_l); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci pr_debug("msg_tx_queue has a cmd to send\n"); 9862306a36Sopenharmony_ci while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { 9962306a36Sopenharmony_ci r = nfc_llc_xmit_from_hci(hdev->llc, skb); 10062306a36Sopenharmony_ci if (r < 0) { 10162306a36Sopenharmony_ci kfree_skb(skb); 10262306a36Sopenharmony_ci skb_queue_purge(&msg->msg_frags); 10362306a36Sopenharmony_ci if (msg->cb) 10462306a36Sopenharmony_ci msg->cb(msg->cb_context, NULL, r); 10562306a36Sopenharmony_ci kfree(msg); 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (r) 11162306a36Sopenharmony_ci goto next_msg; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (msg->wait_response == false) { 11462306a36Sopenharmony_ci kfree(msg); 11562306a36Sopenharmony_ci goto next_msg; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci hdev->cmd_pending_msg = msg; 11962306a36Sopenharmony_ci mod_timer(&hdev->cmd_timer, jiffies + 12062306a36Sopenharmony_ci msecs_to_jiffies(hdev->cmd_pending_msg->completion_delay)); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciexit: 12362306a36Sopenharmony_ci mutex_unlock(&hdev->msg_tx_mutex); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void nfc_hci_msg_rx_work(struct work_struct *work) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, 12962306a36Sopenharmony_ci msg_rx_work); 13062306a36Sopenharmony_ci struct sk_buff *skb; 13162306a36Sopenharmony_ci const struct hcp_message *message; 13262306a36Sopenharmony_ci u8 pipe; 13362306a36Sopenharmony_ci u8 type; 13462306a36Sopenharmony_ci u8 instruction; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci while ((skb = skb_dequeue(&hdev->msg_rx_queue)) != NULL) { 13762306a36Sopenharmony_ci pipe = skb->data[0]; 13862306a36Sopenharmony_ci skb_pull(skb, NFC_HCI_HCP_PACKET_HEADER_LEN); 13962306a36Sopenharmony_ci message = (struct hcp_message *)skb->data; 14062306a36Sopenharmony_ci type = HCP_MSG_GET_TYPE(message->header); 14162306a36Sopenharmony_ci instruction = HCP_MSG_GET_CMD(message->header); 14262306a36Sopenharmony_ci skb_pull(skb, NFC_HCI_HCP_MESSAGE_HEADER_LEN); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, skb); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, 14962306a36Sopenharmony_ci struct sk_buff *skb) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci del_timer_sync(&hdev->cmd_timer); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (hdev->cmd_pending_msg->cb) 15462306a36Sopenharmony_ci hdev->cmd_pending_msg->cb(hdev->cmd_pending_msg->cb_context, 15562306a36Sopenharmony_ci skb, err); 15662306a36Sopenharmony_ci else 15762306a36Sopenharmony_ci kfree_skb(skb); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci kfree(hdev->cmd_pending_msg); 16062306a36Sopenharmony_ci hdev->cmd_pending_msg = NULL; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci schedule_work(&hdev->msg_tx_work); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_civoid nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, 16662306a36Sopenharmony_ci struct sk_buff *skb) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci mutex_lock(&hdev->msg_tx_mutex); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (hdev->cmd_pending_msg == NULL) { 17162306a36Sopenharmony_ci kfree_skb(skb); 17262306a36Sopenharmony_ci goto exit; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci __nfc_hci_cmd_completion(hdev, nfc_hci_result_to_errno(result), skb); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciexit: 17862306a36Sopenharmony_ci mutex_unlock(&hdev->msg_tx_mutex); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_civoid nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, 18262306a36Sopenharmony_ci struct sk_buff *skb) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci u8 status = NFC_HCI_ANY_OK; 18562306a36Sopenharmony_ci const struct hci_create_pipe_resp *create_info; 18662306a36Sopenharmony_ci const struct hci_delete_pipe_noti *delete_info; 18762306a36Sopenharmony_ci const struct hci_all_pipe_cleared_noti *cleared_info; 18862306a36Sopenharmony_ci u8 gate; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci pr_debug("from pipe %x cmd %x\n", pipe, cmd); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (pipe >= NFC_HCI_MAX_PIPES) { 19362306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 19462306a36Sopenharmony_ci goto exit; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci gate = hdev->pipes[pipe].gate; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci switch (cmd) { 20062306a36Sopenharmony_ci case NFC_HCI_ADM_NOTIFY_PIPE_CREATED: 20162306a36Sopenharmony_ci if (skb->len != 5) { 20262306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 20362306a36Sopenharmony_ci goto exit; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci create_info = (struct hci_create_pipe_resp *)skb->data; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (create_info->pipe >= NFC_HCI_MAX_PIPES) { 20862306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 20962306a36Sopenharmony_ci goto exit; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Save the new created pipe and bind with local gate, 21362306a36Sopenharmony_ci * the description for skb->data[3] is destination gate id 21462306a36Sopenharmony_ci * but since we received this cmd from host controller, we 21562306a36Sopenharmony_ci * are the destination and it is our local gate 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci hdev->gate2pipe[create_info->dest_gate] = create_info->pipe; 21862306a36Sopenharmony_ci hdev->pipes[create_info->pipe].gate = create_info->dest_gate; 21962306a36Sopenharmony_ci hdev->pipes[create_info->pipe].dest_host = 22062306a36Sopenharmony_ci create_info->src_host; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case NFC_HCI_ANY_OPEN_PIPE: 22362306a36Sopenharmony_ci if (gate == NFC_HCI_INVALID_GATE) { 22462306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 22562306a36Sopenharmony_ci goto exit; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci case NFC_HCI_ADM_NOTIFY_PIPE_DELETED: 22962306a36Sopenharmony_ci if (skb->len != 1) { 23062306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 23162306a36Sopenharmony_ci goto exit; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci delete_info = (struct hci_delete_pipe_noti *)skb->data; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (delete_info->pipe >= NFC_HCI_MAX_PIPES) { 23662306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 23762306a36Sopenharmony_ci goto exit; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci hdev->pipes[delete_info->pipe].gate = NFC_HCI_INVALID_GATE; 24162306a36Sopenharmony_ci hdev->pipes[delete_info->pipe].dest_host = NFC_HCI_INVALID_HOST; 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci case NFC_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED: 24462306a36Sopenharmony_ci if (skb->len != 1) { 24562306a36Sopenharmony_ci status = NFC_HCI_ANY_E_NOK; 24662306a36Sopenharmony_ci goto exit; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci cleared_info = (struct hci_all_pipe_cleared_noti *)skb->data; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci nfc_hci_reset_pipes_per_host(hdev, cleared_info->host); 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci pr_info("Discarded unknown cmd %x to gate %x\n", cmd, gate); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (hdev->ops->cmd_received) 25862306a36Sopenharmony_ci hdev->ops->cmd_received(hdev, pipe, cmd, skb); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciexit: 26162306a36Sopenharmony_ci nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_RESPONSE, 26262306a36Sopenharmony_ci status, NULL, 0, NULL, NULL, 0); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci kfree_skb(skb); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciu32 nfc_hci_sak_to_protocol(u8 sak) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci switch (NFC_HCI_TYPE_A_SEL_PROT(sak)) { 27062306a36Sopenharmony_ci case NFC_HCI_TYPE_A_SEL_PROT_MIFARE: 27162306a36Sopenharmony_ci return NFC_PROTO_MIFARE_MASK; 27262306a36Sopenharmony_ci case NFC_HCI_TYPE_A_SEL_PROT_ISO14443: 27362306a36Sopenharmony_ci return NFC_PROTO_ISO14443_MASK; 27462306a36Sopenharmony_ci case NFC_HCI_TYPE_A_SEL_PROT_DEP: 27562306a36Sopenharmony_ci return NFC_PROTO_NFC_DEP_MASK; 27662306a36Sopenharmony_ci case NFC_HCI_TYPE_A_SEL_PROT_ISO14443_DEP: 27762306a36Sopenharmony_ci return NFC_PROTO_ISO14443_MASK | NFC_PROTO_NFC_DEP_MASK; 27862306a36Sopenharmony_ci default: 27962306a36Sopenharmony_ci return 0xffffffff; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_sak_to_protocol); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciint nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct nfc_target *targets; 28762306a36Sopenharmony_ci struct sk_buff *atqa_skb = NULL; 28862306a36Sopenharmony_ci struct sk_buff *sak_skb = NULL; 28962306a36Sopenharmony_ci struct sk_buff *uid_skb = NULL; 29062306a36Sopenharmony_ci int r; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci pr_debug("from gate %d\n", gate); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL); 29562306a36Sopenharmony_ci if (targets == NULL) 29662306a36Sopenharmony_ci return -ENOMEM; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci switch (gate) { 29962306a36Sopenharmony_ci case NFC_HCI_RF_READER_A_GATE: 30062306a36Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE, 30162306a36Sopenharmony_ci NFC_HCI_RF_READER_A_ATQA, &atqa_skb); 30262306a36Sopenharmony_ci if (r < 0) 30362306a36Sopenharmony_ci goto exit; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE, 30662306a36Sopenharmony_ci NFC_HCI_RF_READER_A_SAK, &sak_skb); 30762306a36Sopenharmony_ci if (r < 0) 30862306a36Sopenharmony_ci goto exit; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (atqa_skb->len != 2 || sak_skb->len != 1) { 31162306a36Sopenharmony_ci r = -EPROTO; 31262306a36Sopenharmony_ci goto exit; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci targets->supported_protocols = 31662306a36Sopenharmony_ci nfc_hci_sak_to_protocol(sak_skb->data[0]); 31762306a36Sopenharmony_ci if (targets->supported_protocols == 0xffffffff) { 31862306a36Sopenharmony_ci r = -EPROTO; 31962306a36Sopenharmony_ci goto exit; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci targets->sens_res = be16_to_cpu(*(__be16 *)atqa_skb->data); 32362306a36Sopenharmony_ci targets->sel_res = sak_skb->data[0]; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE, 32662306a36Sopenharmony_ci NFC_HCI_RF_READER_A_UID, &uid_skb); 32762306a36Sopenharmony_ci if (r < 0) 32862306a36Sopenharmony_ci goto exit; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (uid_skb->len == 0 || uid_skb->len > NFC_NFCID1_MAXSIZE) { 33162306a36Sopenharmony_ci r = -EPROTO; 33262306a36Sopenharmony_ci goto exit; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci memcpy(targets->nfcid1, uid_skb->data, uid_skb->len); 33662306a36Sopenharmony_ci targets->nfcid1_len = uid_skb->len; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (hdev->ops->complete_target_discovered) { 33962306a36Sopenharmony_ci r = hdev->ops->complete_target_discovered(hdev, gate, 34062306a36Sopenharmony_ci targets); 34162306a36Sopenharmony_ci if (r < 0) 34262306a36Sopenharmony_ci goto exit; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci case NFC_HCI_RF_READER_B_GATE: 34662306a36Sopenharmony_ci targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci if (hdev->ops->target_from_gate) 35062306a36Sopenharmony_ci r = hdev->ops->target_from_gate(hdev, gate, targets); 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci r = -EPROTO; 35362306a36Sopenharmony_ci if (r < 0) 35462306a36Sopenharmony_ci goto exit; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (hdev->ops->complete_target_discovered) { 35762306a36Sopenharmony_ci r = hdev->ops->complete_target_discovered(hdev, gate, 35862306a36Sopenharmony_ci targets); 35962306a36Sopenharmony_ci if (r < 0) 36062306a36Sopenharmony_ci goto exit; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* if driver set the new gate, we will skip the old one */ 36662306a36Sopenharmony_ci if (targets->hci_reader_gate == 0x00) 36762306a36Sopenharmony_ci targets->hci_reader_gate = gate; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci r = nfc_targets_found(hdev->ndev, targets, 1); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ciexit: 37262306a36Sopenharmony_ci kfree(targets); 37362306a36Sopenharmony_ci kfree_skb(atqa_skb); 37462306a36Sopenharmony_ci kfree_skb(sak_skb); 37562306a36Sopenharmony_ci kfree_skb(uid_skb); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return r; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_target_discovered); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_civoid nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, 38262306a36Sopenharmony_ci struct sk_buff *skb) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci int r = 0; 38562306a36Sopenharmony_ci u8 gate; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (pipe >= NFC_HCI_MAX_PIPES) { 38862306a36Sopenharmony_ci pr_err("Discarded event %x to invalid pipe %x\n", event, pipe); 38962306a36Sopenharmony_ci goto exit; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci gate = hdev->pipes[pipe].gate; 39362306a36Sopenharmony_ci if (gate == NFC_HCI_INVALID_GATE) { 39462306a36Sopenharmony_ci pr_err("Discarded event %x to unopened pipe %x\n", event, pipe); 39562306a36Sopenharmony_ci goto exit; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (hdev->ops->event_received) { 39962306a36Sopenharmony_ci r = hdev->ops->event_received(hdev, pipe, event, skb); 40062306a36Sopenharmony_ci if (r <= 0) 40162306a36Sopenharmony_ci goto exit_noskb; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci switch (event) { 40562306a36Sopenharmony_ci case NFC_HCI_EVT_TARGET_DISCOVERED: 40662306a36Sopenharmony_ci if (skb->len < 1) { /* no status data? */ 40762306a36Sopenharmony_ci r = -EPROTO; 40862306a36Sopenharmony_ci goto exit; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (skb->data[0] == 3) { 41262306a36Sopenharmony_ci /* TODO: Multiple targets in field, none activated 41362306a36Sopenharmony_ci * poll is supposedly stopped, but there is no 41462306a36Sopenharmony_ci * single target to activate, so nothing to report 41562306a36Sopenharmony_ci * up. 41662306a36Sopenharmony_ci * if we need to restart poll, we must save the 41762306a36Sopenharmony_ci * protocols from the initial poll and reuse here. 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (skb->data[0] != 0) { 42262306a36Sopenharmony_ci r = -EPROTO; 42362306a36Sopenharmony_ci goto exit; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci r = nfc_hci_target_discovered(hdev, gate); 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci pr_info("Discarded unknown event %x to gate %x\n", event, gate); 43062306a36Sopenharmony_ci r = -EINVAL; 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ciexit: 43562306a36Sopenharmony_ci kfree_skb(skb); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ciexit_noskb: 43862306a36Sopenharmony_ci if (r) 43962306a36Sopenharmony_ci nfc_hci_driver_failure(hdev, r); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void nfc_hci_cmd_timeout(struct timer_list *t) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct nfc_hci_dev *hdev = from_timer(hdev, t, cmd_timer); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci schedule_work(&hdev->msg_tx_work); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, 45062306a36Sopenharmony_ci const struct nfc_hci_gate *gates) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci int r; 45362306a36Sopenharmony_ci while (gate_count--) { 45462306a36Sopenharmony_ci r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, 45562306a36Sopenharmony_ci gates->gate, gates->pipe); 45662306a36Sopenharmony_ci if (r < 0) 45762306a36Sopenharmony_ci return r; 45862306a36Sopenharmony_ci gates++; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int hci_dev_session_init(struct nfc_hci_dev *hdev) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct sk_buff *skb = NULL; 46762306a36Sopenharmony_ci int r; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (hdev->init_data.gates[0].gate != NFC_HCI_ADMIN_GATE) 47062306a36Sopenharmony_ci return -EPROTO; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, 47362306a36Sopenharmony_ci hdev->init_data.gates[0].gate, 47462306a36Sopenharmony_ci hdev->init_data.gates[0].pipe); 47562306a36Sopenharmony_ci if (r < 0) 47662306a36Sopenharmony_ci goto exit; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE, 47962306a36Sopenharmony_ci NFC_HCI_ADMIN_SESSION_IDENTITY, &skb); 48062306a36Sopenharmony_ci if (r < 0) 48162306a36Sopenharmony_ci goto disconnect_all; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (skb->len && skb->len == strlen(hdev->init_data.session_id) && 48462306a36Sopenharmony_ci (memcmp(hdev->init_data.session_id, skb->data, 48562306a36Sopenharmony_ci skb->len) == 0) && hdev->ops->load_session) { 48662306a36Sopenharmony_ci /* Restore gate<->pipe table from some proprietary location. */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci r = hdev->ops->load_session(hdev); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (r < 0) 49162306a36Sopenharmony_ci goto disconnect_all; 49262306a36Sopenharmony_ci } else { 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci r = nfc_hci_disconnect_all_gates(hdev); 49562306a36Sopenharmony_ci if (r < 0) 49662306a36Sopenharmony_ci goto exit; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, 49962306a36Sopenharmony_ci hdev->init_data.gates); 50062306a36Sopenharmony_ci if (r < 0) 50162306a36Sopenharmony_ci goto disconnect_all; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, 50462306a36Sopenharmony_ci NFC_HCI_ADMIN_SESSION_IDENTITY, 50562306a36Sopenharmony_ci hdev->init_data.session_id, 50662306a36Sopenharmony_ci strlen(hdev->init_data.session_id)); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci if (r == 0) 50962306a36Sopenharmony_ci goto exit; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cidisconnect_all: 51262306a36Sopenharmony_ci nfc_hci_disconnect_all_gates(hdev); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ciexit: 51562306a36Sopenharmony_ci kfree_skb(skb); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return r; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int hci_dev_version(struct nfc_hci_dev *hdev) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci int r; 52362306a36Sopenharmony_ci struct sk_buff *skb; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, 52662306a36Sopenharmony_ci NFC_HCI_ID_MGMT_VERSION_SW, &skb); 52762306a36Sopenharmony_ci if (r == -EOPNOTSUPP) { 52862306a36Sopenharmony_ci pr_info("Software/Hardware info not available\n"); 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci if (r < 0) 53262306a36Sopenharmony_ci return r; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (skb->len != 3) { 53562306a36Sopenharmony_ci kfree_skb(skb); 53662306a36Sopenharmony_ci return -EINVAL; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci hdev->sw_romlib = (skb->data[0] & 0xf0) >> 4; 54062306a36Sopenharmony_ci hdev->sw_patch = skb->data[0] & 0x0f; 54162306a36Sopenharmony_ci hdev->sw_flashlib_major = skb->data[1]; 54262306a36Sopenharmony_ci hdev->sw_flashlib_minor = skb->data[2]; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci kfree_skb(skb); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, 54762306a36Sopenharmony_ci NFC_HCI_ID_MGMT_VERSION_HW, &skb); 54862306a36Sopenharmony_ci if (r < 0) 54962306a36Sopenharmony_ci return r; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (skb->len != 3) { 55262306a36Sopenharmony_ci kfree_skb(skb); 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci hdev->hw_derivative = (skb->data[0] & 0xe0) >> 5; 55762306a36Sopenharmony_ci hdev->hw_version = skb->data[0] & 0x1f; 55862306a36Sopenharmony_ci hdev->hw_mpw = (skb->data[1] & 0xc0) >> 6; 55962306a36Sopenharmony_ci hdev->hw_software = skb->data[1] & 0x3f; 56062306a36Sopenharmony_ci hdev->hw_bsid = skb->data[2]; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci kfree_skb(skb); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci pr_info("SOFTWARE INFO:\n"); 56562306a36Sopenharmony_ci pr_info("RomLib : %d\n", hdev->sw_romlib); 56662306a36Sopenharmony_ci pr_info("Patch : %d\n", hdev->sw_patch); 56762306a36Sopenharmony_ci pr_info("FlashLib Major : %d\n", hdev->sw_flashlib_major); 56862306a36Sopenharmony_ci pr_info("FlashLib Minor : %d\n", hdev->sw_flashlib_minor); 56962306a36Sopenharmony_ci pr_info("HARDWARE INFO:\n"); 57062306a36Sopenharmony_ci pr_info("Derivative : %d\n", hdev->hw_derivative); 57162306a36Sopenharmony_ci pr_info("HW Version : %d\n", hdev->hw_version); 57262306a36Sopenharmony_ci pr_info("#MPW : %d\n", hdev->hw_mpw); 57362306a36Sopenharmony_ci pr_info("Software : %d\n", hdev->hw_software); 57462306a36Sopenharmony_ci pr_info("BSID Version : %d\n", hdev->hw_bsid); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic int hci_dev_up(struct nfc_dev *nfc_dev) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 58262306a36Sopenharmony_ci int r = 0; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (hdev->ops->open) { 58562306a36Sopenharmony_ci r = hdev->ops->open(hdev); 58662306a36Sopenharmony_ci if (r < 0) 58762306a36Sopenharmony_ci return r; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci r = nfc_llc_start(hdev->llc); 59162306a36Sopenharmony_ci if (r < 0) 59262306a36Sopenharmony_ci goto exit_close; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci r = hci_dev_session_init(hdev); 59562306a36Sopenharmony_ci if (r < 0) 59662306a36Sopenharmony_ci goto exit_llc; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 59962306a36Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 60062306a36Sopenharmony_ci if (r < 0) 60162306a36Sopenharmony_ci goto exit_llc; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (hdev->ops->hci_ready) { 60462306a36Sopenharmony_ci r = hdev->ops->hci_ready(hdev); 60562306a36Sopenharmony_ci if (r < 0) 60662306a36Sopenharmony_ci goto exit_llc; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci r = hci_dev_version(hdev); 61062306a36Sopenharmony_ci if (r < 0) 61162306a36Sopenharmony_ci goto exit_llc; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci return 0; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ciexit_llc: 61662306a36Sopenharmony_ci nfc_llc_stop(hdev->llc); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ciexit_close: 61962306a36Sopenharmony_ci if (hdev->ops->close) 62062306a36Sopenharmony_ci hdev->ops->close(hdev); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return r; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int hci_dev_down(struct nfc_dev *nfc_dev) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci nfc_llc_stop(hdev->llc); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (hdev->ops->close) 63262306a36Sopenharmony_ci hdev->ops->close(hdev); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci nfc_hci_reset_pipes(hdev); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic int hci_start_poll(struct nfc_dev *nfc_dev, 64062306a36Sopenharmony_ci u32 im_protocols, u32 tm_protocols) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (hdev->ops->start_poll) 64562306a36Sopenharmony_ci return hdev->ops->start_poll(hdev, im_protocols, tm_protocols); 64662306a36Sopenharmony_ci else 64762306a36Sopenharmony_ci return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 64862306a36Sopenharmony_ci NFC_HCI_EVT_READER_REQUESTED, 64962306a36Sopenharmony_ci NULL, 0); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void hci_stop_poll(struct nfc_dev *nfc_dev) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (hdev->ops->stop_poll) 65762306a36Sopenharmony_ci hdev->ops->stop_poll(hdev); 65862306a36Sopenharmony_ci else 65962306a36Sopenharmony_ci nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, 66062306a36Sopenharmony_ci NFC_HCI_EVT_END_OPERATION, NULL, 0); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, 66462306a36Sopenharmony_ci __u8 comm_mode, __u8 *gb, size_t gb_len) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (!hdev->ops->dep_link_up) 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci return hdev->ops->dep_link_up(hdev, target, comm_mode, 67262306a36Sopenharmony_ci gb, gb_len); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic int hci_dep_link_down(struct nfc_dev *nfc_dev) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (!hdev->ops->dep_link_down) 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return hdev->ops->dep_link_down(hdev); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int hci_activate_target(struct nfc_dev *nfc_dev, 68662306a36Sopenharmony_ci struct nfc_target *target, u32 protocol) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci return 0; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic void hci_deactivate_target(struct nfc_dev *nfc_dev, 69262306a36Sopenharmony_ci struct nfc_target *target, 69362306a36Sopenharmony_ci u8 mode) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci#define HCI_CB_TYPE_TRANSCEIVE 1 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void hci_transceive_cb(void *context, struct sk_buff *skb, int err) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct nfc_hci_dev *hdev = context; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci switch (hdev->async_cb_type) { 70462306a36Sopenharmony_ci case HCI_CB_TYPE_TRANSCEIVE: 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * TODO: Check RF Error indicator to make sure data is valid. 70762306a36Sopenharmony_ci * It seems that HCI cmd can complete without error, but data 70862306a36Sopenharmony_ci * can be invalid if an RF error occurred? Ignore for now. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (err == 0) 71162306a36Sopenharmony_ci skb_trim(skb, skb->len - 1); /* RF Err ind */ 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci hdev->async_cb(hdev->async_cb_context, skb, err); 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci default: 71662306a36Sopenharmony_ci if (err == 0) 71762306a36Sopenharmony_ci kfree_skb(skb); 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, 72362306a36Sopenharmony_ci struct sk_buff *skb, data_exchange_cb_t cb, 72462306a36Sopenharmony_ci void *cb_context) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 72762306a36Sopenharmony_ci int r; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci pr_debug("target_idx=%d\n", target->idx); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci switch (target->hci_reader_gate) { 73262306a36Sopenharmony_ci case NFC_HCI_RF_READER_A_GATE: 73362306a36Sopenharmony_ci case NFC_HCI_RF_READER_B_GATE: 73462306a36Sopenharmony_ci if (hdev->ops->im_transceive) { 73562306a36Sopenharmony_ci r = hdev->ops->im_transceive(hdev, target, skb, cb, 73662306a36Sopenharmony_ci cb_context); 73762306a36Sopenharmony_ci if (r <= 0) /* handled */ 73862306a36Sopenharmony_ci break; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci *(u8 *)skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci hdev->async_cb_type = HCI_CB_TYPE_TRANSCEIVE; 74462306a36Sopenharmony_ci hdev->async_cb = cb; 74562306a36Sopenharmony_ci hdev->async_cb_context = cb_context; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci r = nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, 74862306a36Sopenharmony_ci NFC_HCI_WR_XCHG_DATA, skb->data, 74962306a36Sopenharmony_ci skb->len, hci_transceive_cb, hdev); 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci default: 75262306a36Sopenharmony_ci if (hdev->ops->im_transceive) { 75362306a36Sopenharmony_ci r = hdev->ops->im_transceive(hdev, target, skb, cb, 75462306a36Sopenharmony_ci cb_context); 75562306a36Sopenharmony_ci if (r == 1) 75662306a36Sopenharmony_ci r = -ENOTSUPP; 75762306a36Sopenharmony_ci } else { 75862306a36Sopenharmony_ci r = -ENOTSUPP; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci kfree_skb(skb); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return r; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic int hci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (!hdev->ops->tm_send) { 77362306a36Sopenharmony_ci kfree_skb(skb); 77462306a36Sopenharmony_ci return -ENOTSUPP; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return hdev->ops->tm_send(hdev, skb); 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int hci_check_presence(struct nfc_dev *nfc_dev, 78162306a36Sopenharmony_ci struct nfc_target *target) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (!hdev->ops->check_presence) 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci return hdev->ops->check_presence(hdev, target); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic int hci_discover_se(struct nfc_dev *nfc_dev) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (hdev->ops->discover_se) 79662306a36Sopenharmony_ci return hdev->ops->discover_se(hdev); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int hci_enable_se(struct nfc_dev *nfc_dev, u32 se_idx) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (hdev->ops->enable_se) 80662306a36Sopenharmony_ci return hdev->ops->enable_se(hdev, se_idx); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic int hci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (hdev->ops->disable_se) 81662306a36Sopenharmony_ci return hdev->ops->disable_se(hdev, se_idx); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci return 0; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic int hci_se_io(struct nfc_dev *nfc_dev, u32 se_idx, 82262306a36Sopenharmony_ci u8 *apdu, size_t apdu_length, 82362306a36Sopenharmony_ci se_io_cb_t cb, void *cb_context) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (hdev->ops->se_io) 82862306a36Sopenharmony_ci return hdev->ops->se_io(hdev, se_idx, apdu, 82962306a36Sopenharmony_ci apdu_length, cb, cb_context); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci mutex_lock(&hdev->msg_tx_mutex); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (hdev->cmd_pending_msg == NULL) { 83962306a36Sopenharmony_ci nfc_driver_failure(hdev->ndev, err); 84062306a36Sopenharmony_ci goto exit; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci __nfc_hci_cmd_completion(hdev, err, NULL); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ciexit: 84662306a36Sopenharmony_ci mutex_unlock(&hdev->msg_tx_mutex); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci nfc_hci_failure(hdev, err); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci struct hcp_packet *packet; 85762306a36Sopenharmony_ci u8 type; 85862306a36Sopenharmony_ci u8 instruction; 85962306a36Sopenharmony_ci struct sk_buff *hcp_skb; 86062306a36Sopenharmony_ci u8 pipe; 86162306a36Sopenharmony_ci struct sk_buff *frag_skb; 86262306a36Sopenharmony_ci int msg_len; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci packet = (struct hcp_packet *)skb->data; 86562306a36Sopenharmony_ci if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { 86662306a36Sopenharmony_ci skb_queue_tail(&hdev->rx_hcp_frags, skb); 86762306a36Sopenharmony_ci return; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* it's the last fragment. Does it need re-aggregation? */ 87162306a36Sopenharmony_ci if (skb_queue_len(&hdev->rx_hcp_frags)) { 87262306a36Sopenharmony_ci pipe = packet->header & NFC_HCI_FRAGMENT; 87362306a36Sopenharmony_ci skb_queue_tail(&hdev->rx_hcp_frags, skb); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci msg_len = 0; 87662306a36Sopenharmony_ci skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { 87762306a36Sopenharmony_ci msg_len += (frag_skb->len - 87862306a36Sopenharmony_ci NFC_HCI_HCP_PACKET_HEADER_LEN); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + 88262306a36Sopenharmony_ci msg_len, GFP_KERNEL); 88362306a36Sopenharmony_ci if (hcp_skb == NULL) { 88462306a36Sopenharmony_ci nfc_hci_failure(hdev, -ENOMEM); 88562306a36Sopenharmony_ci return; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci skb_put_u8(hcp_skb, pipe); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { 89162306a36Sopenharmony_ci msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; 89262306a36Sopenharmony_ci skb_put_data(hcp_skb, 89362306a36Sopenharmony_ci frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, 89462306a36Sopenharmony_ci msg_len); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci skb_queue_purge(&hdev->rx_hcp_frags); 89862306a36Sopenharmony_ci } else { 89962306a36Sopenharmony_ci packet->header &= NFC_HCI_FRAGMENT; 90062306a36Sopenharmony_ci hcp_skb = skb; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* if this is a response, dispatch immediately to 90462306a36Sopenharmony_ci * unblock waiting cmd context. Otherwise, enqueue to dispatch 90562306a36Sopenharmony_ci * in separate context where handler can also execute command. 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_ci packet = (struct hcp_packet *)hcp_skb->data; 90862306a36Sopenharmony_ci type = HCP_MSG_GET_TYPE(packet->message.header); 90962306a36Sopenharmony_ci if (type == NFC_HCI_HCP_RESPONSE) { 91062306a36Sopenharmony_ci pipe = packet->header; 91162306a36Sopenharmony_ci instruction = HCP_MSG_GET_CMD(packet->message.header); 91262306a36Sopenharmony_ci skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + 91362306a36Sopenharmony_ci NFC_HCI_HCP_MESSAGE_HEADER_LEN); 91462306a36Sopenharmony_ci nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); 91562306a36Sopenharmony_ci } else { 91662306a36Sopenharmony_ci skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); 91762306a36Sopenharmony_ci schedule_work(&hdev->msg_rx_work); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic int hci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (!hdev->ops->fw_download) 92662306a36Sopenharmony_ci return -ENOTSUPP; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci return hdev->ops->fw_download(hdev, firmware_name); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic const struct nfc_ops hci_nfc_ops = { 93262306a36Sopenharmony_ci .dev_up = hci_dev_up, 93362306a36Sopenharmony_ci .dev_down = hci_dev_down, 93462306a36Sopenharmony_ci .start_poll = hci_start_poll, 93562306a36Sopenharmony_ci .stop_poll = hci_stop_poll, 93662306a36Sopenharmony_ci .dep_link_up = hci_dep_link_up, 93762306a36Sopenharmony_ci .dep_link_down = hci_dep_link_down, 93862306a36Sopenharmony_ci .activate_target = hci_activate_target, 93962306a36Sopenharmony_ci .deactivate_target = hci_deactivate_target, 94062306a36Sopenharmony_ci .im_transceive = hci_transceive, 94162306a36Sopenharmony_ci .tm_send = hci_tm_send, 94262306a36Sopenharmony_ci .check_presence = hci_check_presence, 94362306a36Sopenharmony_ci .fw_download = hci_fw_download, 94462306a36Sopenharmony_ci .discover_se = hci_discover_se, 94562306a36Sopenharmony_ci .enable_se = hci_enable_se, 94662306a36Sopenharmony_ci .disable_se = hci_disable_se, 94762306a36Sopenharmony_ci .se_io = hci_se_io, 94862306a36Sopenharmony_ci}; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistruct nfc_hci_dev *nfc_hci_allocate_device(const struct nfc_hci_ops *ops, 95162306a36Sopenharmony_ci struct nfc_hci_init_data *init_data, 95262306a36Sopenharmony_ci unsigned long quirks, 95362306a36Sopenharmony_ci u32 protocols, 95462306a36Sopenharmony_ci const char *llc_name, 95562306a36Sopenharmony_ci int tx_headroom, 95662306a36Sopenharmony_ci int tx_tailroom, 95762306a36Sopenharmony_ci int max_link_payload) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct nfc_hci_dev *hdev; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (ops->xmit == NULL) 96262306a36Sopenharmony_ci return NULL; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (protocols == 0) 96562306a36Sopenharmony_ci return NULL; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci hdev = kzalloc(sizeof(struct nfc_hci_dev), GFP_KERNEL); 96862306a36Sopenharmony_ci if (hdev == NULL) 96962306a36Sopenharmony_ci return NULL; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci hdev->llc = nfc_llc_allocate(llc_name, hdev, ops->xmit, 97262306a36Sopenharmony_ci nfc_hci_recv_from_llc, tx_headroom, 97362306a36Sopenharmony_ci tx_tailroom, nfc_hci_llc_failure); 97462306a36Sopenharmony_ci if (hdev->llc == NULL) { 97562306a36Sopenharmony_ci kfree(hdev); 97662306a36Sopenharmony_ci return NULL; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, 98062306a36Sopenharmony_ci tx_headroom + HCI_CMDS_HEADROOM, 98162306a36Sopenharmony_ci tx_tailroom); 98262306a36Sopenharmony_ci if (!hdev->ndev) { 98362306a36Sopenharmony_ci nfc_llc_free(hdev->llc); 98462306a36Sopenharmony_ci kfree(hdev); 98562306a36Sopenharmony_ci return NULL; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci hdev->ops = ops; 98962306a36Sopenharmony_ci hdev->max_data_link_payload = max_link_payload; 99062306a36Sopenharmony_ci hdev->init_data = *init_data; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci nfc_set_drvdata(hdev->ndev, hdev); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci nfc_hci_reset_pipes(hdev); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci hdev->quirks = quirks; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci return hdev; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_allocate_device); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_civoid nfc_hci_free_device(struct nfc_hci_dev *hdev) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci nfc_free_device(hdev->ndev); 100562306a36Sopenharmony_ci nfc_llc_free(hdev->llc); 100662306a36Sopenharmony_ci kfree(hdev); 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_free_device); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ciint nfc_hci_register_device(struct nfc_hci_dev *hdev) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci mutex_init(&hdev->msg_tx_mutex); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci INIT_LIST_HEAD(&hdev->msg_tx_queue); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci timer_setup(&hdev->cmd_timer, nfc_hci_cmd_timeout, 0); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci skb_queue_head_init(&hdev->rx_hcp_frags); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci skb_queue_head_init(&hdev->msg_rx_queue); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci return nfc_register_device(hdev->ndev); 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_register_device); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_civoid nfc_hci_unregister_device(struct nfc_hci_dev *hdev) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct hci_msg *msg, *n; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci mutex_lock(&hdev->msg_tx_mutex); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (hdev->cmd_pending_msg) { 103762306a36Sopenharmony_ci if (hdev->cmd_pending_msg->cb) 103862306a36Sopenharmony_ci hdev->cmd_pending_msg->cb( 103962306a36Sopenharmony_ci hdev->cmd_pending_msg->cb_context, 104062306a36Sopenharmony_ci NULL, -ESHUTDOWN); 104162306a36Sopenharmony_ci kfree(hdev->cmd_pending_msg); 104262306a36Sopenharmony_ci hdev->cmd_pending_msg = NULL; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci hdev->shutting_down = true; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci mutex_unlock(&hdev->msg_tx_mutex); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci del_timer_sync(&hdev->cmd_timer); 105062306a36Sopenharmony_ci cancel_work_sync(&hdev->msg_tx_work); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci cancel_work_sync(&hdev->msg_rx_work); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci nfc_unregister_device(hdev->ndev); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci skb_queue_purge(&hdev->rx_hcp_frags); 105762306a36Sopenharmony_ci skb_queue_purge(&hdev->msg_rx_queue); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci list_for_each_entry_safe(msg, n, &hdev->msg_tx_queue, msg_l) { 106062306a36Sopenharmony_ci list_del(&msg->msg_l); 106162306a36Sopenharmony_ci skb_queue_purge(&msg->msg_frags); 106262306a36Sopenharmony_ci kfree(msg); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_unregister_device); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_civoid nfc_hci_set_clientdata(struct nfc_hci_dev *hdev, void *clientdata) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci hdev->clientdata = clientdata; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_set_clientdata); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_civoid *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci return hdev->clientdata; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_get_clientdata); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_civoid nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci nfc_hci_failure(hdev, err); 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_driver_failure); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_civoid nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci nfc_llc_rcv_from_drv(hdev->llc, skb); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_hci_recv_frame); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic int __init nfc_hci_init(void) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci return nfc_llc_init(); 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic void __exit nfc_hci_exit(void) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci nfc_llc_exit(); 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cisubsys_initcall(nfc_hci_init); 110262306a36Sopenharmony_cimodule_exit(nfc_hci_exit); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 110562306a36Sopenharmony_ciMODULE_DESCRIPTION("NFC HCI Core"); 1106