diff options
author | Christophe Ricard <christophe.ricard@gmail.com> | 2016-04-30 03:12:52 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2016-05-03 19:48:16 -0400 |
commit | 1c53855f6be2e7da270e86cae381745ee6105eab (patch) | |
tree | f857a95fd3af940d51015654efe64f360b94d753 /net/nfc | |
parent | 9b8d1a4cf2aa819d606b4e423a6523fc0d4460a2 (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.c | 77 |
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 | } |
401 | EXPORT_SYMBOL(nci_core_init); | 401 | EXPORT_SYMBOL(nci_core_init); |
402 | 402 | ||
403 | struct nci_loopback_data { | ||
404 | u8 conn_id; | ||
405 | struct sk_buff *data; | ||
406 | }; | ||
407 | |||
408 | static 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 | |||
415 | static 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 | |||
431 | int 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 | } | ||
478 | EXPORT_SYMBOL(nci_nfcc_loopback); | ||
479 | |||
403 | static int nci_open_device(struct nci_dev *ndev) | 480 | static int nci_open_device(struct nci_dev *ndev) |
404 | { | 481 | { |
405 | int rc = 0; | 482 | int rc = 0; |