From af9c8aa67d07adcd3b41fb2934af7af056eabecf Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sun, 1 Feb 2015 22:26:10 +0100 Subject: NFC: nci: Add NFCEE discover support NFCEEs (NFC Execution Environment) have to be explicitly discovered by sending the NCI_OP_NFCEE_DISCOVER_CMD command. The NFCC will respond to this command by telling us how many NFCEEs are connected to it. Then the NFCC sends a notification command for each and every NFCEE connected. Here we implement support for sending NCI_OP_NFCEE_DISCOVER_CMD command, receiving the response and the potential notifications. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- include/net/nfc/nci_core.h | 4 ++++ net/nfc/nci/core.c | 17 +++++++++++++++++ net/nfc/nci/ntf.c | 30 ++++++++++++++++++++++++++++++ net/nfc/nci/rsp.c | 21 +++++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 5e508741f208..31ad795aa4b5 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -100,6 +100,8 @@ struct nci_conn_info { struct sk_buff *rx_skb; }; +#define NCI_INVALID_CONN_ID 0x80 + /* NCI Core structures */ struct nci_dev { struct nfc_dev *nfc_dev; @@ -182,6 +184,8 @@ void nci_unregister_device(struct nci_dev *ndev); int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb); int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val); +int nci_nfcee_discover(struct nci_dev *ndev, u8 action); + static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev, unsigned int len, gfp_t how) diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index eb607970bd56..a25857548524 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -469,6 +469,23 @@ int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val) } EXPORT_SYMBOL(nci_set_config); +static void nci_nfcee_discover_req(struct nci_dev *ndev, unsigned long opt) +{ + struct nci_nfcee_discover_cmd cmd; + __u8 action = opt; + + cmd.discovery_action = action; + + nci_send_cmd(ndev, NCI_OP_NFCEE_DISCOVER_CMD, 1, &cmd); +} + +int nci_nfcee_discover(struct nci_dev *ndev, u8 action) +{ + return nci_request(ndev, nci_nfcee_discover_req, action, + msecs_to_jiffies(NCI_CMD_TIMEOUT)); +} +EXPORT_SYMBOL(nci_nfcee_discover); + static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 28fdbe234bd4..4c0be7e82d29 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -713,6 +713,33 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, nci_req_complete(ndev, NCI_STATUS_OK); } +static void nci_nfcee_discover_ntf_packet(struct nci_dev *ndev, + struct sk_buff *skb) +{ + u8 status = NCI_STATUS_OK; + struct nci_conn_info *conn_info; + struct nci_nfcee_discover_ntf *nfcee_ntf = + (struct nci_nfcee_discover_ntf *)skb->data; + + pr_debug("\n"); + + conn_info = devm_kzalloc(&ndev->nfc_dev->dev, + sizeof(struct nci_conn_info), GFP_KERNEL); + if (!conn_info) { + status = NCI_STATUS_REJECTED; + goto exit; + } + + conn_info->id = nfcee_ntf->nfcee_id; + conn_info->conn_id = NCI_INVALID_CONN_ID; + + INIT_LIST_HEAD(&conn_info->list); + list_add(&conn_info->list, &ndev->conn_info_list); + +exit: + nci_req_complete(ndev, status); +} + void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) { __u16 ntf_opcode = nci_opcode(skb->data); @@ -751,6 +778,9 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) nci_rf_deactivate_ntf_packet(ndev, skb); break; + case NCI_OP_NFCEE_DISCOVER_NTF: + nci_nfcee_discover_ntf_packet(ndev, skb); + break; default: pr_err("unknown ntf opcode 0x%x\n", ntf_opcode); break; diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 93b914937263..ee094dfab2ed 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -196,6 +196,23 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, } } +static void nci_nfcee_discover_rsp_packet(struct nci_dev *ndev, + struct sk_buff *skb) +{ + struct nci_nfcee_discover_rsp *discover_rsp; + + if (skb->len != 2) { + nci_req_complete(ndev, NCI_STATUS_NFCEE_PROTOCOL_ERROR); + return; + } + + discover_rsp = (struct nci_nfcee_discover_rsp *)skb->data; + + if (discover_rsp->status != NCI_STATUS_OK || + discover_rsp->num_nfcee == 0) + nci_req_complete(ndev, discover_rsp->status); +} + void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) { __u16 rsp_opcode = nci_opcode(skb->data); @@ -241,6 +258,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) nci_rf_deactivate_rsp_packet(ndev, skb); break; + case NCI_OP_NFCEE_DISCOVER_RSP: + nci_nfcee_discover_rsp_packet(ndev, skb); + break; + default: pr_err("unknown rsp opcode 0x%x\n", rsp_opcode); break; -- cgit v1.2.3