aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Lapuyade <eric.lapuyade@linux.intel.com>2012-09-11 04:43:50 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-09-24 18:17:25 -0400
commitf3e8fb552789f4845e60b11c47b676d14b9488e5 (patch)
tree8fde55db141d361952cbb190d9e59231e143157b
parente4c4789e55327e5f2bd6cafcccd46f9b6251bbc3 (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>
-rw-r--r--drivers/nfc/pn544_hci.c57
-rw-r--r--include/net/nfc/hci.h8
-rw-r--r--include/net/nfc/shdlc.h4
-rw-r--r--net/nfc/hci/core.c57
-rw-r--r--net/nfc/hci/shdlc.c5
5 files changed, 92 insertions, 39 deletions
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
index d90aecfce739..a176d1f7bbf3 100644
--- a/drivers/nfc/pn544_hci.c
+++ b/drivers/nfc/pn544_hci.c
@@ -148,6 +148,9 @@ struct pn544_hci_info {
148 * < 0 if hardware error occured (e.g. i2c err) 148 * < 0 if hardware error occured (e.g. i2c err)
149 * and prevents normal operation. 149 * and prevents normal operation.
150 */ 150 */
151 int async_cb_type;
152 data_exchange_cb_t async_cb;
153 void *async_cb_context;
151}; 154};
152 155
153static void pn544_hci_platform_init(struct pn544_hci_info *info) 156static void pn544_hci_platform_init(struct pn544_hci_info *info)
@@ -731,6 +734,26 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
731 return r; 734 return r;
732} 735}
733 736
737#define PN544_CB_TYPE_READER_F 1
738
739static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
740 int err)
741{
742 struct pn544_hci_info *info = context;
743
744 switch (info->async_cb_type) {
745 case PN544_CB_TYPE_READER_F:
746 if (err == 0)
747 skb_pull(skb, 1);
748 info->async_cb(info->async_cb_context, skb, err);
749 break;
750 default:
751 if (err == 0)
752 kfree_skb(skb);
753 break;
754 }
755}
756
734#define MIFARE_CMD_AUTH_KEY_A 0x60 757#define MIFARE_CMD_AUTH_KEY_A 0x60
735#define MIFARE_CMD_AUTH_KEY_B 0x61 758#define MIFARE_CMD_AUTH_KEY_B 0x61
736#define MIFARE_CMD_HEADER 2 759#define MIFARE_CMD_HEADER 2
@@ -744,11 +767,11 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
744 */ 767 */
745static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, 768static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
746 struct nfc_target *target, 769 struct nfc_target *target,
747 struct sk_buff *skb, 770 struct sk_buff *skb, data_exchange_cb_t cb,
748 struct sk_buff **res_skb) 771 void *cb_context)
749{ 772{
773 struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
750 struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); 774 struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
751 int r;
752 775
753 pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, 776 pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
754 target->hci_reader_gate); 777 target->hci_reader_gate);
@@ -773,25 +796,29 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
773 memcpy(data, uid, MIFARE_UID_LEN); 796 memcpy(data, uid, MIFARE_UID_LEN);
774 } 797 }
775 798
776 return nfc_hci_send_cmd(hdev, target->hci_reader_gate, 799 return nfc_hci_send_cmd_async(hdev,
777 PN544_MIFARE_CMD, 800 target->hci_reader_gate,
778 skb->data, skb->len, res_skb); 801 PN544_MIFARE_CMD,
802 skb->data, skb->len,
803 cb, cb_context);
779 } else 804 } else
780 return 1; 805 return 1;
781 case PN544_RF_READER_F_GATE: 806 case PN544_RF_READER_F_GATE:
782 *skb_push(skb, 1) = 0; 807 *skb_push(skb, 1) = 0;
783 *skb_push(skb, 1) = 0; 808 *skb_push(skb, 1) = 0;
784 809
785 r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, 810 info->async_cb_type = PN544_CB_TYPE_READER_F;
786 PN544_FELICA_RAW, 811 info->async_cb = cb;
787 skb->data, skb->len, res_skb); 812 info->async_cb_context = cb_context;
788 if (r == 0) 813
789 skb_pull(*res_skb, 1); 814 return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
790 return r; 815 PN544_FELICA_RAW, skb->data,
816 skb->len,
817 pn544_hci_data_exchange_cb, info);
791 case PN544_RF_READER_JEWEL_GATE: 818 case PN544_RF_READER_JEWEL_GATE:
792 return nfc_hci_send_cmd(hdev, target->hci_reader_gate, 819 return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
793 PN544_JEWEL_RAW_CMD, 820 PN544_JEWEL_RAW_CMD, skb->data,
794 skb->data, skb->len, res_skb); 821 skb->len, cb, cb_context);
795 default: 822 default:
796 return 1; 823 return 1;
797 } 824 }
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 54ba2caab4a6..6cee6e21fc46 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -38,8 +38,8 @@ struct nfc_hci_ops {
38 int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, 38 int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
39 struct nfc_target *target); 39 struct nfc_target *target);
40 int (*data_exchange) (struct nfc_hci_dev *hdev, 40 int (*data_exchange) (struct nfc_hci_dev *hdev,
41 struct nfc_target *target, 41 struct nfc_target *target, struct sk_buff *skb,
42 struct sk_buff *skb, struct sk_buff **res_skb); 42 data_exchange_cb_t cb, void *cb_context);
43 int (*check_presence)(struct nfc_hci_dev *hdev, 43 int (*check_presence)(struct nfc_hci_dev *hdev,
44 struct nfc_target *target); 44 struct nfc_target *target);
45}; 45};
@@ -103,6 +103,10 @@ struct nfc_hci_dev {
103 u8 hw_mpw; 103 u8 hw_mpw;
104 u8 hw_software; 104 u8 hw_software;
105 u8 hw_bsid; 105 u8 hw_bsid;
106
107 int async_cb_type;
108 data_exchange_cb_t async_cb;
109 void *async_cb_context;
106}; 110};
107 111
108/* hci device allocation */ 112/* hci device allocation */
diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h
index 342427362989..fe5e19829352 100644
--- a/include/net/nfc/shdlc.h
+++ b/include/net/nfc/shdlc.h
@@ -34,8 +34,8 @@ struct nfc_shdlc_ops {
34 int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate, 34 int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate,
35 struct nfc_target *target); 35 struct nfc_target *target);
36 int (*data_exchange) (struct nfc_shdlc *shdlc, 36 int (*data_exchange) (struct nfc_shdlc *shdlc,
37 struct nfc_target *target, 37 struct nfc_target *target, struct sk_buff *skb,
38 struct sk_buff *skb, struct sk_buff **res_skb); 38 data_exchange_cb_t cb, void *cb_context);
39 int (*check_presence)(struct nfc_shdlc *shdlc, 39 int (*check_presence)(struct nfc_shdlc *shdlc,
40 struct nfc_target *target); 40 struct nfc_target *target);
41}; 41};
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
542static 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
540static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, 565static 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
590static int hci_check_presence(struct nfc_dev *nfc_dev, 611static 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,
777static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, 777static 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}