diff options
author | Eric Lapuyade <eric.lapuyade@linux.intel.com> | 2012-09-11 10:43:50 +0200 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-09-25 00:17:25 +0200 |
commit | f3e8fb552789f4845e60b11c47b676d14b9488e5 (patch) | |
tree | 8fde55db141d361952cbb190d9e59231e143157b /drivers/nfc | |
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')
-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 d90aecfce73..a176d1f7bbf 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -148,6 +148,9 @@ struct pn544_hci_info { * < 0 if hardware error occured (e.g. i2c err) * and prevents normal operation. */ + int async_cb_type; + data_exchange_cb_t async_cb; + void *async_cb_context; }; 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, return r; } +#define PN544_CB_TYPE_READER_F 1 + +static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb, + int err) +{ + struct pn544_hci_info *info = context; + + switch (info->async_cb_type) { + case PN544_CB_TYPE_READER_F: + if (err == 0) + skb_pull(skb, 1); + info->async_cb(info->async_cb_context, skb, err); + break; + default: + if (err == 0) + kfree_skb(skb); + break; + } +} + #define MIFARE_CMD_AUTH_KEY_A 0x60 #define MIFARE_CMD_AUTH_KEY_B 0x61 #define MIFARE_CMD_HEADER 2 @@ -744,11 +767,11 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, */ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, struct nfc_target *target, - struct sk_buff *skb, - struct sk_buff **res_skb) + struct sk_buff *skb, data_exchange_cb_t cb, + void *cb_context) { + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); - int r; pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, target->hci_reader_gate); @@ -773,25 +796,29 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, memcpy(data, uid, MIFARE_UID_LEN); } - return nfc_hci_send_cmd(hdev, target->hci_reader_gate, - PN544_MIFARE_CMD, - skb->data, skb->len, res_skb); + return nfc_hci_send_cmd_async(hdev, + target->hci_reader_gate, + PN544_MIFARE_CMD, + skb->data, skb->len, + cb, cb_context); } else return 1; case PN544_RF_READER_F_GATE: *skb_push(skb, 1) = 0; *skb_push(skb, 1) = 0; - r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, - PN544_FELICA_RAW, - skb->data, skb->len, res_skb); - if (r == 0) - skb_pull(*res_skb, 1); - return r; + info->async_cb_type = PN544_CB_TYPE_READER_F; + info->async_cb = cb; + info->async_cb_context = cb_context; + + return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, + PN544_FELICA_RAW, skb->data, + skb->len, + pn544_hci_data_exchange_cb, info); case PN544_RF_READER_JEWEL_GATE: - return nfc_hci_send_cmd(hdev, target->hci_reader_gate, - PN544_JEWEL_RAW_CMD, - skb->data, skb->len, res_skb); + return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, + PN544_JEWEL_RAW_CMD, skb->data, + skb->len, cb, cb_context); default: return 1; } |