aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2016-04-30 03:12:52 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2016-05-03 19:48:16 -0400
commit1c53855f6be2e7da270e86cae381745ee6105eab (patch)
treef857a95fd3af940d51015654efe64f360b94d753 /net/nfc
parent9b8d1a4cf2aa819d606b4e423a6523fc0d4460a2 (diff)
nfc: nci: Add nci_nfcc_loopback to the nci core
For test purpose, provide the generic nci loopback function. Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/nci/core.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 74f2d54df4fc..61fff422424f 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -400,6 +400,83 @@ int nci_core_init(struct nci_dev *ndev)
400} 400}
401EXPORT_SYMBOL(nci_core_init); 401EXPORT_SYMBOL(nci_core_init);
402 402
403struct nci_loopback_data {
404 u8 conn_id;
405 struct sk_buff *data;
406};
407
408static void nci_send_data_req(struct nci_dev *ndev, unsigned long opt)
409{
410 struct nci_loopback_data *data = (struct nci_loopback_data *)opt;
411
412 nci_send_data(ndev, data->conn_id, data->data);
413}
414
415static void nci_nfcc_loopback_cb(void *context, struct sk_buff *skb, int err)
416{
417 struct nci_dev *ndev = (struct nci_dev *)context;
418 struct nci_conn_info *conn_info;
419
420 conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
421 if (!conn_info) {
422 nci_req_complete(ndev, NCI_STATUS_REJECTED);
423 return;
424 }
425
426 conn_info->rx_skb = skb;
427
428 nci_req_complete(ndev, NCI_STATUS_OK);
429}
430
431int nci_nfcc_loopback(struct nci_dev *ndev, void *data, size_t data_len,
432 struct sk_buff **resp)
433{
434 int r;
435 struct nci_loopback_data loopback_data;
436 struct nci_conn_info *conn_info;
437 struct sk_buff *skb;
438 int conn_id = nci_get_conn_info_by_dest_type_params(ndev,
439 NCI_DESTINATION_NFCC_LOOPBACK, NULL);
440
441 if (conn_id < 0) {
442 r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCC_LOOPBACK,
443 0, 0, NULL);
444 if (r != NCI_STATUS_OK)
445 return r;
446
447 conn_id = nci_get_conn_info_by_dest_type_params(ndev,
448 NCI_DESTINATION_NFCC_LOOPBACK,
449 NULL);
450 }
451
452 conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
453 if (!conn_info)
454 return -EPROTO;
455
456 /* store cb and context to be used on receiving data */
457 conn_info->data_exchange_cb = nci_nfcc_loopback_cb;
458 conn_info->data_exchange_cb_context = ndev;
459
460 skb = nci_skb_alloc(ndev, NCI_DATA_HDR_SIZE + data_len, GFP_KERNEL);
461 if (!skb)
462 return -ENOMEM;
463
464 skb_reserve(skb, NCI_DATA_HDR_SIZE);
465 memcpy(skb_put(skb, data_len), data, data_len);
466
467 loopback_data.conn_id = conn_id;
468 loopback_data.data = skb;
469
470 ndev->cur_conn_id = conn_id;
471 r = nci_request(ndev, nci_send_data_req, (unsigned long)&loopback_data,
472 msecs_to_jiffies(NCI_DATA_TIMEOUT));
473 if (r == NCI_STATUS_OK && resp)
474 *resp = conn_info->rx_skb;
475
476 return r;
477}
478EXPORT_SYMBOL(nci_nfcc_loopback);
479
403static int nci_open_device(struct nci_dev *ndev) 480static int nci_open_device(struct nci_dev *ndev)
404{ 481{
405 int rc = 0; 482 int rc = 0;