diff options
author | Eric Lapuyade <eric.lapuyade@linux.intel.com> | 2012-09-11 04:43:50 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-09-24 18:17:25 -0400 |
commit | f3e8fb552789f4845e60b11c47b676d14b9488e5 (patch) | |
tree | 8fde55db141d361952cbb190d9e59231e143157b /net | |
parent | e4c4789e55327e5f2bd6cafcccd46f9b6251bbc3 (diff) |
NFC: Modified hci_transceive to become an asynchronous operation
This enables the completion callback to be called from a different
context, preventing a possible deadlock if the callback resulted in the
invocation of a nested call to the currently locked nfc_dev.
This is also more in line with the im_transceive nfc_ops for NFC Core or
NCI drivers which already behave asynchronously.
Signed-off-by: Eric Lapuyade <eric.lapuyade@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/hci/core.c | 57 | ||||
-rw-r--r-- | net/nfc/hci/shdlc.c | 5 |
2 files changed, 42 insertions, 20 deletions
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index e387c86e0cc7..dc57e3dc15a4 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -537,13 +537,37 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev, | |||
537 | { | 537 | { |
538 | } | 538 | } |
539 | 539 | ||
540 | #define HCI_CB_TYPE_TRANSCEIVE 1 | ||
541 | |||
542 | static void hci_transceive_cb(void *context, struct sk_buff *skb, int err) | ||
543 | { | ||
544 | struct nfc_hci_dev *hdev = context; | ||
545 | |||
546 | switch (hdev->async_cb_type) { | ||
547 | case HCI_CB_TYPE_TRANSCEIVE: | ||
548 | /* | ||
549 | * TODO: Check RF Error indicator to make sure data is valid. | ||
550 | * It seems that HCI cmd can complete without error, but data | ||
551 | * can be invalid if an RF error occured? Ignore for now. | ||
552 | */ | ||
553 | if (err == 0) | ||
554 | skb_trim(skb, skb->len - 1); /* RF Err ind */ | ||
555 | |||
556 | hdev->async_cb(hdev->async_cb_context, skb, err); | ||
557 | break; | ||
558 | default: | ||
559 | if (err == 0) | ||
560 | kfree_skb(skb); | ||
561 | break; | ||
562 | } | ||
563 | } | ||
564 | |||
540 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 565 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
541 | struct sk_buff *skb, data_exchange_cb_t cb, | 566 | struct sk_buff *skb, data_exchange_cb_t cb, |
542 | void *cb_context) | 567 | void *cb_context) |
543 | { | 568 | { |
544 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 569 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
545 | int r; | 570 | int r; |
546 | struct sk_buff *res_skb = NULL; | ||
547 | 571 | ||
548 | pr_debug("target_idx=%d\n", target->idx); | 572 | pr_debug("target_idx=%d\n", target->idx); |
549 | 573 | ||
@@ -551,40 +575,37 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
551 | case NFC_HCI_RF_READER_A_GATE: | 575 | case NFC_HCI_RF_READER_A_GATE: |
552 | case NFC_HCI_RF_READER_B_GATE: | 576 | case NFC_HCI_RF_READER_B_GATE: |
553 | if (hdev->ops->data_exchange) { | 577 | if (hdev->ops->data_exchange) { |
554 | r = hdev->ops->data_exchange(hdev, target, skb, | 578 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
555 | &res_skb); | 579 | cb_context); |
556 | if (r <= 0) /* handled */ | 580 | if (r <= 0) /* handled */ |
557 | break; | 581 | break; |
558 | } | 582 | } |
559 | 583 | ||
560 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ | 584 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ |
561 | r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 585 | |
562 | NFC_HCI_WR_XCHG_DATA, | 586 | hdev->async_cb_type = HCI_CB_TYPE_TRANSCEIVE; |
563 | skb->data, skb->len, &res_skb); | 587 | hdev->async_cb = cb; |
564 | /* | 588 | hdev->async_cb_context = cb_context; |
565 | * TODO: Check RF Error indicator to make sure data is valid. | 589 | |
566 | * It seems that HCI cmd can complete without error, but data | 590 | r = nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
567 | * can be invalid if an RF error occured? Ignore for now. | 591 | NFC_HCI_WR_XCHG_DATA, skb->data, |
568 | */ | 592 | skb->len, hci_transceive_cb, hdev); |
569 | if (r == 0) | ||
570 | skb_trim(res_skb, res_skb->len - 1); /* RF Err ind */ | ||
571 | break; | 593 | break; |
572 | default: | 594 | default: |
573 | if (hdev->ops->data_exchange) { | 595 | if (hdev->ops->data_exchange) { |
574 | r = hdev->ops->data_exchange(hdev, target, skb, | 596 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
575 | &res_skb); | 597 | cb_context); |
576 | if (r == 1) | 598 | if (r == 1) |
577 | r = -ENOTSUPP; | 599 | r = -ENOTSUPP; |
578 | } | 600 | } |
579 | else | 601 | else |
580 | r = -ENOTSUPP; | 602 | r = -ENOTSUPP; |
603 | break; | ||
581 | } | 604 | } |
582 | 605 | ||
583 | kfree_skb(skb); | 606 | kfree_skb(skb); |
584 | 607 | ||
585 | cb(cb_context, res_skb, r); | 608 | return r; |
586 | |||
587 | return 0; | ||
588 | } | 609 | } |
589 | 610 | ||
590 | static int hci_check_presence(struct nfc_dev *nfc_dev, | 611 | static int hci_check_presence(struct nfc_dev *nfc_dev, |
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 9357ba7362f6..c63af7d3e859 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c | |||
@@ -777,12 +777,13 @@ static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev, | |||
777 | static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, | 777 | static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, |
778 | struct nfc_target *target, | 778 | struct nfc_target *target, |
779 | struct sk_buff *skb, | 779 | struct sk_buff *skb, |
780 | struct sk_buff **res_skb) | 780 | data_exchange_cb_t cb, void *cb_context) |
781 | { | 781 | { |
782 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | 782 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); |
783 | 783 | ||
784 | if (shdlc->ops->data_exchange) | 784 | if (shdlc->ops->data_exchange) |
785 | return shdlc->ops->data_exchange(shdlc, target, skb, res_skb); | 785 | return shdlc->ops->data_exchange(shdlc, target, skb, cb, |
786 | cb_context); | ||
786 | 787 | ||
787 | return -EPERM; | 788 | return -EPERM; |
788 | } | 789 | } |