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>
This commit is contained in:

committed by
Samuel Ortiz

parent
e4c4789e55
commit
f3e8fb5527
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user