summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/nfc/nci.h26
-rw-r--r--include/net/nfc/nci_core.h3
-rw-r--r--include/net/nfc/nfc.h2
-rw-r--r--include/uapi/linux/nfc.h20
-rw-r--r--net/nfc/nci/ntf.c133
5 files changed, 146 insertions, 38 deletions
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h
index 36cf65386b86..fffadc706e06 100644
--- a/include/net/nfc/nci.h
+++ b/include/net/nfc/nci.h
@@ -28,6 +28,8 @@
#ifndef __NCI_H
#define __NCI_H
+#include <net/nfc/nfc.h>
+
/* NCI constants */
#define NCI_MAX_NUM_MAPPING_CONFIGS 10
#define NCI_MAX_NUM_RF_CONFIGS 10
@@ -73,6 +75,8 @@
#define NCI_NFC_A_ACTIVE_LISTEN_MODE 0x83
#define NCI_NFC_F_ACTIVE_LISTEN_MODE 0x85
+#define NCI_RF_TECH_MODE_LISTEN_MASK 0x80
+
/* NCI RF Technologies */
#define NCI_NFC_RF_TECHNOLOGY_A 0x00
#define NCI_NFC_RF_TECHNOLOGY_B 0x01
@@ -324,26 +328,31 @@ struct nci_core_intf_error_ntf {
struct rf_tech_specific_params_nfca_poll {
__u16 sens_res;
__u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */
- __u8 nfcid1[10];
+ __u8 nfcid1[NFC_NFCID1_MAXSIZE];
__u8 sel_res_len; /* 0 or 1 Bytes */
__u8 sel_res;
} __packed;
struct rf_tech_specific_params_nfcb_poll {
__u8 sensb_res_len;
- __u8 sensb_res[12]; /* 11 or 12 Bytes */
+ __u8 sensb_res[NFC_SENSB_RES_MAXSIZE]; /* 11 or 12 Bytes */
} __packed;
struct rf_tech_specific_params_nfcf_poll {
__u8 bit_rate;
__u8 sensf_res_len;
- __u8 sensf_res[18]; /* 16 or 18 Bytes */
+ __u8 sensf_res[NFC_SENSF_RES_MAXSIZE]; /* 16 or 18 Bytes */
} __packed;
struct rf_tech_specific_params_nfcv_poll {
__u8 res_flags;
__u8 dsfid;
- __u8 uid[8]; /* 8 Bytes */
+ __u8 uid[NFC_ISO15693_UID_MAXSIZE]; /* 8 Bytes */
+} __packed;
+
+struct rf_tech_specific_params_nfcf_listen {
+ __u8 local_nfcid2_len;
+ __u8 local_nfcid2[NFC_NFCID2_MAXSIZE]; /* 0 or 8 Bytes */
} __packed;
struct nci_rf_discover_ntf {
@@ -375,7 +384,12 @@ struct activation_params_nfcb_poll_iso_dep {
struct activation_params_poll_nfc_dep {
__u8 atr_res_len;
- __u8 atr_res[63];
+ __u8 atr_res[NFC_ATR_RES_MAXSIZE - 2]; /* ATR_RES from byte 3 */
+};
+
+struct activation_params_listen_nfc_dep {
+ __u8 atr_req_len;
+ __u8 atr_req[NFC_ATR_REQ_MAXSIZE - 2]; /* ATR_REQ from byte 3 */
};
struct nci_rf_intf_activated_ntf {
@@ -392,6 +406,7 @@ struct nci_rf_intf_activated_ntf {
struct rf_tech_specific_params_nfcb_poll nfcb_poll;
struct rf_tech_specific_params_nfcf_poll nfcf_poll;
struct rf_tech_specific_params_nfcv_poll nfcv_poll;
+ struct rf_tech_specific_params_nfcf_listen nfcf_listen;
} rf_tech_specific_params;
__u8 data_exch_rf_tech_and_mode;
@@ -403,6 +418,7 @@ struct nci_rf_intf_activated_ntf {
struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep;
struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep;
struct activation_params_poll_nfc_dep poll_nfc_dep;
+ struct activation_params_listen_nfc_dep listen_nfc_dep;
} activation_params;
} __packed;
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index 75d10e625c49..cfea60748a39 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -4,6 +4,7 @@
*
* Copyright (C) 2011 Texas Instruments, Inc.
* Copyright (C) 2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2014 Marvell International Ltd.
*
* Written by Ilan Elias <ilane@ti.com>
*
@@ -49,6 +50,8 @@ enum nci_state {
NCI_W4_ALL_DISCOVERIES,
NCI_W4_HOST_SELECT,
NCI_POLL_ACTIVE,
+ NCI_LISTEN_ACTIVE,
+ NCI_LISTEN_SLEEP,
};
/* NCI timeouts */
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 6c583e244de2..12adb817c27a 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Instituto Nokia de Tecnologia
+ * Copyright (C) 2014 Marvell International Ltd.
*
* Authors:
* Lauro Ramos Venancio <lauro.venancio@openbossa.org>
@@ -87,6 +88,7 @@ struct nfc_ops {
#define NFC_TARGET_IDX_ANY -1
#define NFC_MAX_GT_LEN 48
#define NFC_ATR_RES_GT_OFFSET 15
+#define NFC_ATR_REQ_GT_OFFSET 14
/**
* struct nfc_target - NFC target descriptiom
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 9b19b4461928..19a75daac14c 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -196,15 +196,17 @@ enum nfc_sdp_attr {
};
#define NFC_SDP_ATTR_MAX (__NFC_SDP_ATTR_AFTER_LAST - 1)
-#define NFC_DEVICE_NAME_MAXSIZE 8
-#define NFC_NFCID1_MAXSIZE 10
-#define NFC_NFCID2_MAXSIZE 8
-#define NFC_NFCID3_MAXSIZE 10
-#define NFC_SENSB_RES_MAXSIZE 12
-#define NFC_SENSF_RES_MAXSIZE 18
-#define NFC_GB_MAXSIZE 48
-#define NFC_FIRMWARE_NAME_MAXSIZE 32
-#define NFC_ISO15693_UID_MAXSIZE 8
+#define NFC_DEVICE_NAME_MAXSIZE 8
+#define NFC_NFCID1_MAXSIZE 10
+#define NFC_NFCID2_MAXSIZE 8
+#define NFC_NFCID3_MAXSIZE 10
+#define NFC_SENSB_RES_MAXSIZE 12
+#define NFC_SENSF_RES_MAXSIZE 18
+#define NFC_ATR_REQ_MAXSIZE 64
+#define NFC_ATR_RES_MAXSIZE 64
+#define NFC_GB_MAXSIZE 48
+#define NFC_FIRMWARE_NAME_MAXSIZE 32
+#define NFC_ISO15693_UID_MAXSIZE 8
/* NFC protocols */
#define NFC_PROTO_JEWEL 1
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index 205b35f666db..46b2a90ac55a 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -167,6 +167,18 @@ static __u8 *nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev,
return data;
}
+static __u8 *nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev,
+ struct rf_tech_specific_params_nfcf_listen *nfcf_listen,
+ __u8 *data)
+{
+ nfcf_listen->local_nfcid2_len = min_t(__u8, *data++,
+ NFC_NFCID2_MAXSIZE);
+ memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len);
+ data += nfcf_listen->local_nfcid2_len;
+
+ return data;
+}
+
__u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol)
{
if (ndev->ops->get_rfprotocol)
@@ -401,17 +413,29 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
{
struct activation_params_poll_nfc_dep *poll;
+ struct activation_params_listen_nfc_dep *listen;
switch (ntf->activation_rf_tech_and_mode) {
case NCI_NFC_A_PASSIVE_POLL_MODE:
case NCI_NFC_F_PASSIVE_POLL_MODE:
poll = &ntf->activation_params.poll_nfc_dep;
- poll->atr_res_len = min_t(__u8, *data++, 63);
+ poll->atr_res_len = min_t(__u8, *data++,
+ NFC_ATR_RES_MAXSIZE - 2);
pr_debug("atr_res_len %d\n", poll->atr_res_len);
if (poll->atr_res_len > 0)
memcpy(poll->atr_res, data, poll->atr_res_len);
break;
+ case NCI_NFC_A_PASSIVE_LISTEN_MODE:
+ case NCI_NFC_F_PASSIVE_LISTEN_MODE:
+ listen = &ntf->activation_params.listen_nfc_dep;
+ listen->atr_req_len = min_t(__u8, *data++,
+ NFC_ATR_REQ_MAXSIZE - 2);
+ pr_debug("atr_req_len %d\n", listen->atr_req_len);
+ if (listen->atr_req_len > 0)
+ memcpy(listen->atr_req, data, listen->atr_req_len);
+ break;
+
default:
pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
ntf->activation_rf_tech_and_mode);
@@ -444,6 +468,50 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets);
}
+static int nci_store_general_bytes_nfc_dep(struct nci_dev *ndev,
+ struct nci_rf_intf_activated_ntf *ntf)
+{
+ ndev->remote_gb_len = 0;
+
+ if (ntf->activation_params_len <= 0)
+ return NCI_STATUS_OK;
+
+ switch (ntf->activation_rf_tech_and_mode) {
+ case NCI_NFC_A_PASSIVE_POLL_MODE:
+ case NCI_NFC_F_PASSIVE_POLL_MODE:
+ /* ATR_RES general bytes at offset 15 */
+ ndev->remote_gb_len = min_t(__u8,
+ (ntf->activation_params.poll_nfc_dep.atr_res_len
+ - NFC_ATR_RES_GT_OFFSET),
+ NFC_MAX_GT_LEN);
+ memcpy(ndev->remote_gb,
+ (ntf->activation_params.poll_nfc_dep .atr_res
+ + NFC_ATR_RES_GT_OFFSET),
+ ndev->remote_gb_len);
+ break;
+
+ case NCI_NFC_A_PASSIVE_LISTEN_MODE:
+ case NCI_NFC_F_PASSIVE_LISTEN_MODE:
+ /* ATR_REQ general bytes at offset 14 */
+ ndev->remote_gb_len = min_t(__u8,
+ (ntf->activation_params.listen_nfc_dep.atr_req_len
+ - NFC_ATR_REQ_GT_OFFSET),
+ NFC_MAX_GT_LEN);
+ memcpy(ndev->remote_gb,
+ (ntf->activation_params.listen_nfc_dep.atr_req
+ + NFC_ATR_REQ_GT_OFFSET),
+ ndev->remote_gb_len);
+ break;
+
+ default:
+ pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
+ ntf->activation_rf_tech_and_mode);
+ return NCI_STATUS_RF_PROTOCOL_ERROR;
+ }
+
+ return NCI_STATUS_OK;
+}
+
static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
struct sk_buff *skb)
{
@@ -493,6 +561,16 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
&(ntf.rf_tech_specific_params.nfcv_poll), data);
break;
+ case NCI_NFC_A_PASSIVE_LISTEN_MODE:
+ /* no RF technology specific parameters */
+ break;
+
+ case NCI_NFC_F_PASSIVE_LISTEN_MODE:
+ data = nci_extract_rf_params_nfcf_passive_listen(ndev,
+ &(ntf.rf_tech_specific_params.nfcf_listen),
+ data);
+ break;
+
default:
pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
ntf.activation_rf_tech_and_mode);
@@ -546,32 +624,39 @@ exit:
/* store general bytes to be reported later in dep_link_up */
if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) {
- ndev->remote_gb_len = 0;
-
- if (ntf.activation_params_len > 0) {
- /* ATR_RES general bytes at offset 15 */
- ndev->remote_gb_len = min_t(__u8,
- (ntf.activation_params
- .poll_nfc_dep.atr_res_len
- - NFC_ATR_RES_GT_OFFSET),
- NFC_MAX_GT_LEN);
- memcpy(ndev->remote_gb,
- (ntf.activation_params.poll_nfc_dep
- .atr_res + NFC_ATR_RES_GT_OFFSET),
- ndev->remote_gb_len);
- }
+ err = nci_store_general_bytes_nfc_dep(ndev, &ntf);
+ if (err != NCI_STATUS_OK)
+ pr_err("unable to store general bytes\n");
}
}
- if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
- /* A single target was found and activated automatically */
- atomic_set(&ndev->state, NCI_POLL_ACTIVE);
- if (err == NCI_STATUS_OK)
- nci_target_auto_activated(ndev, &ntf);
- } else { /* ndev->state == NCI_W4_HOST_SELECT */
- /* A selected target was activated, so complete the request */
- atomic_set(&ndev->state, NCI_POLL_ACTIVE);
- nci_req_complete(ndev, err);
+ if (!(ntf.activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK)) {
+ /* Poll mode */
+ if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
+ /* A single target was found and activated
+ * automatically */
+ atomic_set(&ndev->state, NCI_POLL_ACTIVE);
+ if (err == NCI_STATUS_OK)
+ nci_target_auto_activated(ndev, &ntf);
+ } else { /* ndev->state == NCI_W4_HOST_SELECT */
+ /* A selected target was activated, so complete the
+ * request */
+ atomic_set(&ndev->state, NCI_POLL_ACTIVE);
+ nci_req_complete(ndev, err);
+ }
+ } else {
+ /* Listen mode */
+ atomic_set(&ndev->state, NCI_LISTEN_ACTIVE);
+ if (err == NCI_STATUS_OK &&
+ ntf.rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) {
+ err = nfc_tm_activated(ndev->nfc_dev,
+ NFC_PROTO_NFC_DEP_MASK,
+ NFC_COMM_PASSIVE,
+ ndev->remote_gb,
+ ndev->remote_gb_len);
+ if (err != NCI_STATUS_OK)
+ pr_err("error when signaling tm activation\n");
+ }
}
}