Commit b16ae716 authored by Christophe Ricard's avatar Christophe Ricard Committed by Samuel Ortiz

NFC: nci: Support all destinations type when creating a connection

The current implementation limits nci_core_conn_create_req()
to only manage NCI_DESTINATION_NFCEE.
Add new parameters to nci_core_conn_create() to support all
destination types described in the NCI specification.
Because there are some parameters with variable size dynamic
buffer allocation is needed.
Signed-off-by: default avatarChristophe Ricard <christophe-h.ricard@st.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 12bdf27d
...@@ -494,7 +494,8 @@ EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se); ...@@ -494,7 +494,8 @@ EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se);
static int st21nfcb_hci_network_init(struct nci_dev *ndev) static int st21nfcb_hci_network_init(struct nci_dev *ndev)
{ {
struct core_conn_create_dest_spec_params dest_params; struct core_conn_create_dest_spec_params *dest_params;
struct dest_spec_params spec_params;
struct nci_conn_info *conn_info; struct nci_conn_info *conn_info;
int r, dev_num; int r, dev_num;
...@@ -502,17 +503,29 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev) ...@@ -502,17 +503,29 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
if (r != NCI_STATUS_OK) if (r != NCI_STATUS_OK)
goto exit; goto exit;
dest_params.type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE; dest_params =
dest_params.length = sizeof(struct dest_spec_params); kzalloc(sizeof(struct core_conn_create_dest_spec_params) +
dest_params.value.id = ndev->hci_dev->conn_info->id; sizeof(struct dest_spec_params), GFP_KERNEL);
dest_params.value.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS; if (dest_params == NULL) {
r = nci_core_conn_create(ndev, &dest_params); r = -ENOMEM;
if (r != NCI_STATUS_OK)
goto exit; goto exit;
}
dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE;
dest_params->length = sizeof(struct dest_spec_params);
spec_params.id = ndev->hci_dev->conn_info->id;
spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS;
memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params));
r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1,
sizeof(struct core_conn_create_dest_spec_params) +
sizeof(struct dest_spec_params),
dest_params);
if (r != NCI_STATUS_OK)
goto free_dest_params;
conn_info = ndev->hci_dev->conn_info; conn_info = ndev->hci_dev->conn_info;
if (!conn_info) if (!conn_info)
goto exit; goto free_dest_params;
memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates, memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
sizeof(st21nfcb_gates)); sizeof(st21nfcb_gates));
...@@ -522,8 +535,10 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev) ...@@ -522,8 +535,10 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
* persistent info to discriminate 2 identical chips * persistent info to discriminate 2 identical chips
*/ */
dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES); dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES);
if (dev_num >= ST21NFCB_NUM_DEVICES) if (dev_num >= ST21NFCB_NUM_DEVICES) {
return -ENODEV; r = -ENODEV;
goto free_dest_params;
}
scnprintf(ndev->hci_dev->init_data.session_id, scnprintf(ndev->hci_dev->init_data.session_id,
sizeof(ndev->hci_dev->init_data.session_id), sizeof(ndev->hci_dev->init_data.session_id),
...@@ -540,6 +555,9 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev) ...@@ -540,6 +555,9 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
return 0; return 0;
free_dest_params:
kfree(dest_params);
exit: exit:
return r; return r;
} }
......
...@@ -244,21 +244,23 @@ struct nci_core_set_config_cmd { ...@@ -244,21 +244,23 @@ struct nci_core_set_config_cmd {
} __packed; } __packed;
#define NCI_OP_CORE_CONN_CREATE_CMD nci_opcode_pack(NCI_GID_CORE, 0x04) #define NCI_OP_CORE_CONN_CREATE_CMD nci_opcode_pack(NCI_GID_CORE, 0x04)
#define DEST_SPEC_PARAMS_ID_INDEX 0
#define DEST_SPEC_PARAMS_PROTOCOL_INDEX 1
struct dest_spec_params { struct dest_spec_params {
__u8 id; __u8 id;
__u8 protocol; __u8 protocol;
} __packed; } __packed;
struct core_conn_create_dest_spec_params { struct core_conn_create_dest_spec_params {
__u8 type; __u8 type;
__u8 length; __u8 length;
struct dest_spec_params value; __u8 value[0];
} __packed; } __packed;
struct nci_core_conn_create_cmd { struct nci_core_conn_create_cmd {
__u8 destination_type; __u8 destination_type;
__u8 number_destination_params; __u8 number_destination_params;
struct core_conn_create_dest_spec_params params; struct core_conn_create_dest_spec_params params[0];
} __packed; } __packed;
#define NCI_OP_CORE_CONN_CLOSE_CMD nci_opcode_pack(NCI_GID_CORE, 0x05) #define NCI_OP_CORE_CONN_CLOSE_CMD nci_opcode_pack(NCI_GID_CORE, 0x05)
......
...@@ -263,7 +263,9 @@ int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val); ...@@ -263,7 +263,9 @@ 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); int nci_nfcee_discover(struct nci_dev *ndev, u8 action);
int nci_nfcee_mode_set(struct nci_dev *ndev, u8 nfcee_id, u8 nfcee_mode); int nci_nfcee_mode_set(struct nci_dev *ndev, u8 nfcee_id, u8 nfcee_mode);
int nci_core_conn_create(struct nci_dev *ndev, int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
u8 number_destination_params,
size_t params_len,
struct core_conn_create_dest_spec_params *params); struct core_conn_create_dest_spec_params *params);
int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id); int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id);
......
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#include <net/nfc/nci_core.h> #include <net/nfc/nci_core.h>
#include <linux/nfc.h> #include <linux/nfc.h>
struct core_conn_create_data {
int length;
struct nci_core_conn_create_cmd *cmd;
};
static void nci_cmd_work(struct work_struct *work); static void nci_cmd_work(struct work_struct *work);
static void nci_rx_work(struct work_struct *work); static void nci_rx_work(struct work_struct *work);
static void nci_tx_work(struct work_struct *work); static void nci_tx_work(struct work_struct *work);
...@@ -509,25 +514,38 @@ EXPORT_SYMBOL(nci_nfcee_mode_set); ...@@ -509,25 +514,38 @@ EXPORT_SYMBOL(nci_nfcee_mode_set);
static void nci_core_conn_create_req(struct nci_dev *ndev, unsigned long opt) static void nci_core_conn_create_req(struct nci_dev *ndev, unsigned long opt)
{ {
struct nci_core_conn_create_cmd cmd; struct core_conn_create_data *data =
struct core_conn_create_dest_spec_params *params = (struct core_conn_create_data *)opt;
(struct core_conn_create_dest_spec_params *)opt;
nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, data->length, data->cmd);
cmd.destination_type = NCI_DESTINATION_NFCEE;
cmd.number_destination_params = 1;
memcpy(&cmd.params.type, params,
sizeof(struct core_conn_create_dest_spec_params));
nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD,
sizeof(struct nci_core_conn_create_cmd), &cmd);
} }
int nci_core_conn_create(struct nci_dev *ndev, int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
u8 number_destination_params,
size_t params_len,
struct core_conn_create_dest_spec_params *params) struct core_conn_create_dest_spec_params *params)
{ {
ndev->cur_id = params->value.id; int r;
return nci_request(ndev, nci_core_conn_create_req, struct nci_core_conn_create_cmd *cmd;
(unsigned long)params, struct core_conn_create_data data;
msecs_to_jiffies(NCI_CMD_TIMEOUT));
data.length = params_len + sizeof(struct nci_core_conn_create_cmd);
cmd = kzalloc(data.length, GFP_KERNEL);
if (!cmd)
return -ENOMEM;
cmd->destination_type = destination_type;
cmd->number_destination_params = number_destination_params;
memcpy(cmd->params, params, params_len);
data.cmd = cmd;
ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX];
r = __nci_request(ndev, nci_core_conn_create_req,
(unsigned long)&data,
msecs_to_jiffies(NCI_CMD_TIMEOUT));
kfree(cmd);
return r;
} }
EXPORT_SYMBOL(nci_core_conn_create); EXPORT_SYMBOL(nci_core_conn_create);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment