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 /drivers/nfc/pn544_hci.c | |
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 'drivers/nfc/pn544_hci.c')
-rw-r--r-- | drivers/nfc/pn544_hci.c | 57 |
1 files changed, 42 insertions, 15 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 | ||
153 | static void pn544_hci_platform_init(struct pn544_hci_info *info) | 156 | static 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 | |||
739 | static 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 | */ |
745 | static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, | 768 | static 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 | } |