aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2015-02-03 13:48:05 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2015-02-04 03:10:50 -0500
commitb16ae7160a836c4a1e443ea6efca31421e86bae1 (patch)
tree8d4185e4b41b0d71f5abe293c3183068a129a86c
parent12bdf27d46c9d5e490fa164551642e065105db78 (diff)
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: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb_se.c38
-rw-r--r--include/net/nfc/nci.h18
-rw-r--r--include/net/nfc/nci_core.h4
-rw-r--r--net/nfc/nci/core.c48
4 files changed, 74 insertions, 34 deletions
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st21nfcb/st21nfcb_se.c
index 9f4d8b744f32..3b465e4c85e3 100644
--- a/drivers/nfc/st21nfcb/st21nfcb_se.c
+++ b/drivers/nfc/st21nfcb/st21nfcb_se.c
@@ -494,7 +494,8 @@ EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se);
494 494
495static int st21nfcb_hci_network_init(struct nci_dev *ndev) 495static int st21nfcb_hci_network_init(struct nci_dev *ndev)
496{ 496{
497 struct core_conn_create_dest_spec_params dest_params; 497 struct core_conn_create_dest_spec_params *dest_params;
498 struct dest_spec_params spec_params;
498 struct nci_conn_info *conn_info; 499 struct nci_conn_info *conn_info;
499 int r, dev_num; 500 int r, dev_num;
500 501
@@ -502,17 +503,29 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
502 if (r != NCI_STATUS_OK) 503 if (r != NCI_STATUS_OK)
503 goto exit; 504 goto exit;
504 505
505 dest_params.type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE; 506 dest_params =
506 dest_params.length = sizeof(struct dest_spec_params); 507 kzalloc(sizeof(struct core_conn_create_dest_spec_params) +
507 dest_params.value.id = ndev->hci_dev->conn_info->id; 508 sizeof(struct dest_spec_params), GFP_KERNEL);
508 dest_params.value.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS; 509 if (dest_params == NULL) {
509 r = nci_core_conn_create(ndev, &dest_params); 510 r = -ENOMEM;
510 if (r != NCI_STATUS_OK)
511 goto exit; 511 goto exit;
512 }
513
514 dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE;
515 dest_params->length = sizeof(struct dest_spec_params);
516 spec_params.id = ndev->hci_dev->conn_info->id;
517 spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS;
518 memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params));
519 r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1,
520 sizeof(struct core_conn_create_dest_spec_params) +
521 sizeof(struct dest_spec_params),
522 dest_params);
523 if (r != NCI_STATUS_OK)
524 goto free_dest_params;
512 525
513 conn_info = ndev->hci_dev->conn_info; 526 conn_info = ndev->hci_dev->conn_info;
514 if (!conn_info) 527 if (!conn_info)
515 goto exit; 528 goto free_dest_params;
516 529
517 memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates, 530 memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
518 sizeof(st21nfcb_gates)); 531 sizeof(st21nfcb_gates));
@@ -522,8 +535,10 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
522 * persistent info to discriminate 2 identical chips 535 * persistent info to discriminate 2 identical chips
523 */ 536 */
524 dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES); 537 dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES);
525 if (dev_num >= ST21NFCB_NUM_DEVICES) 538 if (dev_num >= ST21NFCB_NUM_DEVICES) {
526 return -ENODEV; 539 r = -ENODEV;
540 goto free_dest_params;
541 }
527 542
528 scnprintf(ndev->hci_dev->init_data.session_id, 543 scnprintf(ndev->hci_dev->init_data.session_id,
529 sizeof(ndev->hci_dev->init_data.session_id), 544 sizeof(ndev->hci_dev->init_data.session_id),
@@ -540,6 +555,9 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
540 555
541 return 0; 556 return 0;
542 557
558free_dest_params:
559 kfree(dest_params);
560
543exit: 561exit:
544 return r; 562 return r;
545} 563}
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h
index 6c1beb2704b1..695d33cb75e8 100644
--- a/include/net/nfc/nci.h
+++ b/include/net/nfc/nci.h
@@ -244,21 +244,23 @@ struct nci_core_set_config_cmd {
244} __packed; 244} __packed;
245 245
246#define NCI_OP_CORE_CONN_CREATE_CMD nci_opcode_pack(NCI_GID_CORE, 0x04) 246#define NCI_OP_CORE_CONN_CREATE_CMD nci_opcode_pack(NCI_GID_CORE, 0x04)
247#define DEST_SPEC_PARAMS_ID_INDEX 0
248#define DEST_SPEC_PARAMS_PROTOCOL_INDEX 1
247struct dest_spec_params { 249struct dest_spec_params {
248 __u8 id; 250 __u8 id;
249 __u8 protocol; 251 __u8 protocol;
250} __packed; 252} __packed;
251 253
252struct core_conn_create_dest_spec_params { 254struct core_conn_create_dest_spec_params {
253 __u8 type; 255 __u8 type;
254 __u8 length; 256 __u8 length;
255 struct dest_spec_params value; 257 __u8 value[0];
256} __packed; 258} __packed;
257 259
258struct nci_core_conn_create_cmd { 260struct nci_core_conn_create_cmd {
259 __u8 destination_type; 261 __u8 destination_type;
260 __u8 number_destination_params; 262 __u8 number_destination_params;
261 struct core_conn_create_dest_spec_params params; 263 struct core_conn_create_dest_spec_params params[0];
262} __packed; 264} __packed;
263 265
264#define NCI_OP_CORE_CONN_CLOSE_CMD nci_opcode_pack(NCI_GID_CORE, 0x05) 266#define NCI_OP_CORE_CONN_CLOSE_CMD nci_opcode_pack(NCI_GID_CORE, 0x05)
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index 731fa5be9989..d34c1b2295d7 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -263,7 +263,9 @@ int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val);
263 263
264int nci_nfcee_discover(struct nci_dev *ndev, u8 action); 264int nci_nfcee_discover(struct nci_dev *ndev, u8 action);
265int nci_nfcee_mode_set(struct nci_dev *ndev, u8 nfcee_id, u8 nfcee_mode); 265int nci_nfcee_mode_set(struct nci_dev *ndev, u8 nfcee_id, u8 nfcee_mode);
266int nci_core_conn_create(struct nci_dev *ndev, 266int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
267 u8 number_destination_params,
268 size_t params_len,
267 struct core_conn_create_dest_spec_params *params); 269 struct core_conn_create_dest_spec_params *params);
268int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id); 270int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id);
269 271
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 17ff5f83393c..ddfe91e43c88 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -41,6 +41,11 @@
41#include <net/nfc/nci_core.h> 41#include <net/nfc/nci_core.h>
42#include <linux/nfc.h> 42#include <linux/nfc.h>
43 43
44struct core_conn_create_data {
45 int length;
46 struct nci_core_conn_create_cmd *cmd;
47};
48
44static void nci_cmd_work(struct work_struct *work); 49static void nci_cmd_work(struct work_struct *work);
45static void nci_rx_work(struct work_struct *work); 50static void nci_rx_work(struct work_struct *work);
46static void nci_tx_work(struct work_struct *work); 51static void nci_tx_work(struct work_struct *work);
@@ -509,25 +514,38 @@ EXPORT_SYMBOL(nci_nfcee_mode_set);
509 514
510static void nci_core_conn_create_req(struct nci_dev *ndev, unsigned long opt) 515static void nci_core_conn_create_req(struct nci_dev *ndev, unsigned long opt)
511{ 516{
512 struct nci_core_conn_create_cmd cmd; 517 struct core_conn_create_data *data =
513 struct core_conn_create_dest_spec_params *params = 518 (struct core_conn_create_data *)opt;
514 (struct core_conn_create_dest_spec_params *)opt; 519
515 520 nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, data->length, data->cmd);
516 cmd.destination_type = NCI_DESTINATION_NFCEE;
517 cmd.number_destination_params = 1;
518 memcpy(&cmd.params.type, params,
519 sizeof(struct core_conn_create_dest_spec_params));
520 nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD,
521 sizeof(struct nci_core_conn_create_cmd), &cmd);
522} 521}
523 522
524int nci_core_conn_create(struct nci_dev *ndev, 523int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
524 u8 number_destination_params,
525 size_t params_len,
525 struct core_conn_create_dest_spec_params *params) 526 struct core_conn_create_dest_spec_params *params)
526{ 527{
527 ndev->cur_id = params->value.id; 528 int r;
528 return nci_request(ndev, nci_core_conn_create_req, 529 struct nci_core_conn_create_cmd *cmd;
529 (unsigned long)params, 530 struct core_conn_create_data data;
530 msecs_to_jiffies(NCI_CMD_TIMEOUT)); 531
532 data.length = params_len + sizeof(struct nci_core_conn_create_cmd);
533 cmd = kzalloc(data.length, GFP_KERNEL);
534 if (!cmd)
535 return -ENOMEM;
536
537 cmd->destination_type = destination_type;
538 cmd->number_destination_params = number_destination_params;
539 memcpy(cmd->params, params, params_len);
540
541 data.cmd = cmd;
542 ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX];
543
544 r = __nci_request(ndev, nci_core_conn_create_req,
545 (unsigned long)&data,
546 msecs_to_jiffies(NCI_CMD_TIMEOUT));
547 kfree(cmd);
548 return r;
531} 549}
532EXPORT_SYMBOL(nci_core_conn_create); 550EXPORT_SYMBOL(nci_core_conn_create);
533 551