Skip to content

Commit

Permalink
NFC: Add NCI multiple targets support
Browse files Browse the repository at this point in the history
Add the ability to select between multiple targets in NCI.
If only one target is found, it will be auto-activated.
If more than one target is found, then DISCOVER_NTF will be
generated for each target, and the host should select one by
calling DISCOVER_SELECT_CMD. Then, the target will be activated.
If the activation fails, GENERIC_ERROR_NTF is generated.

Signed-off-by: Ilan Elias <ilane@ti.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Ilan Elias authored and John W. Linville committed Jan 24, 2012
1 parent 25a1d9d commit 019c4fb
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 96 deletions.
34 changes: 33 additions & 1 deletion include/net/nfc/nci.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@
#define NCI_DISC_MAP_MODE_POLL 0x01
#define NCI_DISC_MAP_MODE_LISTEN 0x02

/* NCI Discover Notification Type */
#define NCI_DISCOVER_NTF_TYPE_LAST 0x00
#define NCI_DISCOVER_NTF_TYPE_LAST_NFCC 0x01
#define NCI_DISCOVER_NTF_TYPE_MORE 0x02

/* NCI Deactivation Type */
#define NCI_DEACTIVATE_TYPE_IDLE_MODE 0x00
#define NCI_DEACTIVATE_TYPE_SLEEP_MODE 0x01
Expand Down Expand Up @@ -207,6 +212,13 @@ struct nci_rf_disc_cmd {
struct disc_config disc_configs[NCI_MAX_NUM_RF_CONFIGS];
} __packed;

#define NCI_OP_RF_DISCOVER_SELECT_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x04)
struct nci_rf_discover_select_cmd {
__u8 rf_discovery_id;
__u8 rf_protocol;
__u8 rf_interface;
} __packed;

#define NCI_OP_RF_DEACTIVATE_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
struct nci_rf_deactivate_cmd {
__u8 type;
Expand Down Expand Up @@ -244,6 +256,8 @@ struct nci_core_init_rsp_2 {

#define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)

#define NCI_OP_RF_DISCOVER_SELECT_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x04)

#define NCI_OP_RF_DEACTIVATE_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)

/* --------------------------- */
Expand All @@ -260,13 +274,15 @@ struct nci_core_conn_credit_ntf {
struct conn_credit_entry conn_entries[NCI_MAX_NUM_CONN];
} __packed;

#define NCI_OP_CORE_GENERIC_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x07)

#define NCI_OP_CORE_INTF_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x08)
struct nci_core_intf_error_ntf {
__u8 status;
__u8 conn_id;
} __packed;

#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
#define NCI_OP_RF_DISCOVER_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
struct rf_tech_specific_params_nfca_poll {
__u16 sens_res;
__u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */
Expand All @@ -286,6 +302,22 @@ struct rf_tech_specific_params_nfcf_poll {
__u8 sensf_res[18]; /* 16 or 18 Bytes */
} __packed;

struct nci_rf_discover_ntf {
__u8 rf_discovery_id;
__u8 rf_protocol;
__u8 rf_tech_and_mode;
__u8 rf_tech_specific_params_len;

union {
struct rf_tech_specific_params_nfca_poll nfca_poll;
struct rf_tech_specific_params_nfcb_poll nfcb_poll;
struct rf_tech_specific_params_nfcf_poll nfcf_poll;
} rf_tech_specific_params;

__u8 ntf_type;
} __packed;

#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
struct activation_params_nfca_poll_iso_dep {
__u8 rats_res_len;
__u8 rats_res[20];
Expand Down
9 changes: 8 additions & 1 deletion include/net/nfc/nci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,16 @@ enum nci_flag {
enum nci_state {
NCI_IDLE,
NCI_DISCOVERY,
NCI_W4_ALL_DISCOVERIES,
NCI_W4_HOST_SELECT,
NCI_POLL_ACTIVE,
};

/* NCI timeouts */
#define NCI_RESET_TIMEOUT 5000
#define NCI_INIT_TIMEOUT 5000
#define NCI_RF_DISC_TIMEOUT 5000
#define NCI_RF_DISC_SELECT_TIMEOUT 5000
#define NCI_RF_DEACTIVATE_TIMEOUT 30000
#define NCI_CMD_TIMEOUT 5000
#define NCI_DATA_TIMEOUT 700
Expand All @@ -66,6 +69,7 @@ struct nci_ops {
};

#define NCI_MAX_SUPPORTED_RF_INTERFACES 4
#define NCI_MAX_DISCOVERED_TARGETS 10

/* NCI Core structures */
struct nci_dev {
Expand Down Expand Up @@ -105,9 +109,11 @@ struct nci_dev {
void *driver_data;

__u32 poll_prots;
__u32 target_available_prots;
__u32 target_active_prot;

struct nfc_target targets[NCI_MAX_DISCOVERED_TARGETS];
int n_targets;

/* received during NCI_OP_CORE_RESET_RSP */
__u8 nci_ver;

Expand Down Expand Up @@ -178,6 +184,7 @@ int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload);
int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb);
void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
int err);
void nci_clear_target_list(struct nci_dev *ndev);

/* ----- NCI requests ----- */
#define NCI_REQ_DONE 0
Expand Down
91 changes: 82 additions & 9 deletions net/nfc/nci/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,39 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
&cmd);
}

struct nci_rf_discover_select_param {
__u8 rf_discovery_id;
__u8 rf_protocol;
};

static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt)
{
struct nci_rf_discover_select_param *param =
(struct nci_rf_discover_select_param *)opt;
struct nci_rf_discover_select_cmd cmd;

cmd.rf_discovery_id = param->rf_discovery_id;
cmd.rf_protocol = param->rf_protocol;

switch (cmd.rf_protocol) {
case NCI_RF_PROTOCOL_ISO_DEP:
cmd.rf_interface = NCI_RF_INTERFACE_ISO_DEP;
break;

case NCI_RF_PROTOCOL_NFC_DEP:
cmd.rf_interface = NCI_RF_INTERFACE_NFC_DEP;
break;

default:
cmd.rf_interface = NCI_RF_INTERFACE_FRAME;
break;
}

nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD,
sizeof(struct nci_rf_discover_select_cmd),
&cmd);
}

static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
{
struct nci_rf_deactivate_cmd cmd;
Expand Down Expand Up @@ -264,6 +297,7 @@ static int nci_open_device(struct nci_dev *ndev)

if (!rc) {
set_bit(NCI_UP, &ndev->flags);
nci_clear_target_list(ndev);
atomic_set(&ndev->state, NCI_IDLE);
} else {
/* Init failed, cleanup */
Expand Down Expand Up @@ -361,7 +395,8 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;

if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
if ((atomic_read(&ndev->state) == NCI_DISCOVERY) ||
(atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) {
pr_err("unable to start poll, since poll is already active\n");
return -EBUSY;
}
Expand All @@ -371,8 +406,9 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
return -EBUSY;
}

if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) {
pr_debug("target is active, implicitly deactivate...\n");
if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) ||
(atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) {
pr_debug("target active or w4 select, implicitly deactivate\n");

rc = nci_request(ndev, nci_rf_deactivate_req, 0,
msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Expand All @@ -393,7 +429,8 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);

if (atomic_read(&ndev->state) != NCI_DISCOVERY) {
if ((atomic_read(&ndev->state) != NCI_DISCOVERY) &&
(atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) {
pr_err("unable to stop poll, since poll is not active\n");
return;
}
Expand All @@ -406,10 +443,15 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
__u32 protocol)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
struct nci_rf_discover_select_param param;
struct nfc_target *target = 0;
int i;
int rc = 0;

pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol);

if (atomic_read(&ndev->state) != NCI_POLL_ACTIVE) {
if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) &&
(atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
pr_err("there is no available target to activate\n");
return -EINVAL;
}
Expand All @@ -419,16 +461,47 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
return -EBUSY;
}

if (!(ndev->target_available_prots & (1 << protocol))) {
for (i = 0; i < ndev->n_targets; i++) {
if (ndev->targets[i].idx == target_idx) {
target = &ndev->targets[i];
break;
}
}

if (!target) {
pr_err("unable to find the selected target\n");
return -EINVAL;
}

if (!(target->supported_protocols & (1 << protocol))) {
pr_err("target does not support the requested protocol 0x%x\n",
protocol);
return -EINVAL;
}

ndev->target_active_prot = protocol;
ndev->target_available_prots = 0;
if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
param.rf_discovery_id = target->idx;

return 0;
if (protocol == NFC_PROTO_JEWEL)
param.rf_protocol = NCI_RF_PROTOCOL_T1T;
else if (protocol == NFC_PROTO_MIFARE)
param.rf_protocol = NCI_RF_PROTOCOL_T2T;
else if (protocol == NFC_PROTO_FELICA)
param.rf_protocol = NCI_RF_PROTOCOL_T3T;
else if (protocol == NFC_PROTO_ISO14443)
param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
else
param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;

rc = nci_request(ndev, nci_rf_discover_select_req,
(unsigned long)&param,
msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
}

if (!rc)
ndev->target_active_prot = protocol;

return rc;
}

static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
Expand Down
Loading

0 comments on commit 019c4fb

Please sign in to comment.