summary refs log tree commit diff
diff options
context:
space:
mode:
authorArron Wang <arron.wang@intel.com>2013-08-23 16:01:58 +0800
committerSamuel Ortiz <sameo@linux.intel.com>2013-09-25 01:35:38 +0200
commit5faba2fdf9819ebebd6d1a1cef70fddb0518cd08 (patch)
treeb9d52b453da916f760424af305df68b029847ace
parentb75ff5e84bb6c2d43a8ec39b240c80f0543821f0 (diff)
downloadlinux-5faba2fdf9819ebebd6d1a1cef70fddb0518cd08.tar.gz
NFC: pn544: Add SE discover operation
For the SWP secure element, we send the proprietary SELF_TEST_SWP
command and check the response.
For the WI secure element, we simply try to switch to the default
embedded SE mode. If that works, it means we have an embedded SE.

Signed-off-by: Arron Wang <arron.wang@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/nfc/pn544/pn544.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index 078e62feba17..727f312e05d2 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -41,6 +41,7 @@ enum pn544_state {
 
 /* Proprietary commands */
 #define PN544_WRITE		0x3f
+#define PN544_TEST_SWP		0x21
 
 /* Proprietary gates, events, commands and registers */
 
@@ -83,12 +84,14 @@ enum pn544_state {
 #define PN544_SWP_MGMT_GATE			0xA0
 
 #define PN544_NFC_WI_MGMT_GATE			0xA1
+#define PN544_NFC_ESE_DEFAULT_MODE		0x01
 
 #define PN544_HCI_EVT_SND_DATA			0x01
 #define PN544_HCI_EVT_ACTIVATED			0x02
 #define PN544_HCI_EVT_DEACTIVATED		0x03
 #define PN544_HCI_EVT_RCV_DATA			0x04
 #define PN544_HCI_EVT_CONTINUE_MI		0x05
+#define PN544_HCI_EVT_SWITCH_MODE		0x03
 
 #define PN544_HCI_CMD_ATTREQUEST		0x12
 #define PN544_HCI_CMD_CONTINUE_ACTIVATION	0x13
@@ -792,6 +795,32 @@ static int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
 	return info->fw_download(info->phy_id, firmware_name);
 }
 
+static int pn544_hci_discover_se(struct nfc_hci_dev *hdev)
+{
+	u32 se_idx = 0;
+	u8 ese_mode = 0x01; /* Default mode */
+	struct sk_buff *res_skb;
+	int r;
+
+	r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP,
+			     NULL, 0, &res_skb);
+
+	if (r == 0) {
+		if (res_skb->len == 2 && res_skb->data[0] == 0x00)
+			nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC);
+
+		kfree_skb(res_skb);
+	}
+
+	r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE,
+				PN544_HCI_EVT_SWITCH_MODE,
+				&ese_mode, 1);
+	if (r == 0)
+		nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED);
+
+	return !se_idx;
+}
+
 static struct nfc_hci_ops pn544_hci_ops = {
 	.open = pn544_hci_open,
 	.close = pn544_hci_close,
@@ -807,6 +836,7 @@ static struct nfc_hci_ops pn544_hci_ops = {
 	.check_presence = pn544_hci_check_presence,
 	.event_received = pn544_hci_event_received,
 	.fw_download = pn544_hci_fw_download,
+	.discover_se = pn544_hci_discover_se,
 };
 
 int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,