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>
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
index d90aecf..a176d1f7 100644
--- a/drivers/nfc/pn544_hci.c
+++ b/drivers/nfc/pn544_hci.c
@@ -148,6 +148,9 @@
 				 * < 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 @@
 	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_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 @@
 				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;
 	}