]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
NFC: digital: Add poll support for type 4A tag platform
authorThierry Escande <thierry.escande@linux.intel.com>
Sun, 26 Jan 2014 23:31:31 +0000 (00:31 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 16 Feb 2014 22:49:54 +0000 (23:49 +0100)
This adds support for ATS request and response handling for type 4A tag
activation.

Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
include/net/nfc/digital.h
net/nfc/digital_core.c
net/nfc/digital_technology.c

index 1f0528d3350040a56551d978f6275832704c23d4..b9699d7dd0391b7b0a6730e689da7b5ba0aae8c9 100644 (file)
@@ -51,6 +51,7 @@ enum {
 
        NFC_DIGITAL_FRAMING_NFCA_T1T,
        NFC_DIGITAL_FRAMING_NFCA_T2T,
+       NFC_DIGITAL_FRAMING_NFCA_T4T,
        NFC_DIGITAL_FRAMING_NFCA_NFC_DEP,
 
        NFC_DIGITAL_FRAMING_NFCF,
@@ -208,6 +209,8 @@ struct nfc_digital_dev {
        u8 curr_rf_tech;
        u8 curr_nfc_dep_pni;
 
+       u16 target_fsc;
+
        int (*skb_check_crc)(struct sk_buff *skb);
        void (*skb_add_crc)(struct sk_buff *skb);
 };
index 48906ca605401806c0d519ac66f7f08ab1755064..e1f240266adf8493c3d7a108f294584944adc6a6 100644 (file)
@@ -337,6 +337,11 @@ int digital_target_found(struct nfc_digital_dev *ddev,
                framing = NFC_DIGITAL_FRAMING_ISO15693_TVT;
                check_crc = digital_skb_check_crc_b;
                add_crc = digital_skb_add_crc_b;
+
+       case NFC_PROTO_ISO14443:
+               framing = NFC_DIGITAL_FRAMING_NFCA_T4T;
+               check_crc = digital_skb_check_crc_a;
+               add_crc = digital_skb_add_crc_a;
                break;
 
        default:
@@ -714,6 +719,8 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
                ddev->protocols |= NFC_PROTO_NFC_DEP_MASK;
        if (supported_protocols & NFC_PROTO_ISO15693_MASK)
                ddev->protocols |= NFC_PROTO_ISO15693_MASK;
+       if (supported_protocols & NFC_PROTO_ISO14443_MASK)
+               ddev->protocols |= NFC_PROTO_ISO14443_MASK;
 
        ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN;
        ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN;
index 97d3f602fc0619748901e999c9c04e38687abae4..6649d9461dff9666447f6cebb5807d2398baf85e 100644 (file)
@@ -30,6 +30,7 @@
 
 #define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04))
 #define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60))
+#define DIGITAL_SEL_RES_IS_T4T(sel_res) ((sel_res) & 0x20)
 #define DIGITAL_SEL_RES_IS_NFC_DEP(sel_res) ((sel_res) & 0x40)
 
 #define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x0C00) == 0x0C00)
 #define DIGITAL_ISO15693_RES_IS_VALID(flags) \
        (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR))
 
+static const u8 digital_ats_fsc[] = {
+        16,  24,  32,  40,  48,  64,  96, 128,
+};
+
+#define DIGITAL_ATS_FSCI(t0) ((t0) & 0x0F)
+#define DIGITAL_ATS_MAX_FSC  256
+
+#define DIGITAL_RATS_BYTE1 0xE0
+#define DIGITAL_RATS_PARAM 0x80
+
 struct digital_sdd_res {
        u8 nfcid1[4];
        u8 bcc;
@@ -107,6 +118,63 @@ struct digital_iso15693_inv_res {
 static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev,
                                   struct nfc_target *target);
 
+static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg,
+                               struct sk_buff *resp)
+{
+       struct nfc_target *target = arg;
+       u8 fsdi;
+       int rc;
+
+       if (IS_ERR(resp)) {
+               rc = PTR_ERR(resp);
+               resp = NULL;
+               goto exit;
+       }
+
+       if (resp->len < 2) {
+               rc = -EIO;
+               goto exit;
+       }
+
+       fsdi = DIGITAL_ATS_FSCI(resp->data[1]);
+       if (fsdi >= 8)
+               ddev->target_fsc = DIGITAL_ATS_MAX_FSC;
+       else
+               ddev->target_fsc = digital_ats_fsc[fsdi];
+
+       ddev->curr_nfc_dep_pni = 0;
+
+       rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443);
+
+exit:
+       dev_kfree_skb(resp);
+       kfree(target);
+
+       if (rc)
+               digital_poll_next_tech(ddev);
+}
+
+static int digital_in_send_rats(struct nfc_digital_dev *ddev,
+                               struct nfc_target *target)
+{
+       int rc;
+       struct sk_buff *skb;
+
+       skb = digital_skb_alloc(ddev, 2);
+       if (!skb)
+               return -ENOMEM;
+
+       *skb_put(skb, 1) = DIGITAL_RATS_BYTE1;
+       *skb_put(skb, 1) = DIGITAL_RATS_PARAM;
+
+       rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_ats,
+                                target);
+       if (rc)
+               kfree_skb(skb);
+
+       return rc;
+}
+
 static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
                                    struct sk_buff *resp)
 {
@@ -144,8 +212,19 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
                goto exit_free_skb;
        }
 
+       target->sel_res = sel_res;
+
        if (DIGITAL_SEL_RES_IS_T2T(sel_res)) {
                nfc_proto = NFC_PROTO_MIFARE;
+       } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) {
+               rc = digital_in_send_rats(ddev, target);
+               if (rc)
+                       goto exit;
+               /*
+                * Skip target_found and don't free it for now. This will be
+                * done when receiving the ATS
+                */
+               goto exit_free_skb;
        } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) {
                nfc_proto = NFC_PROTO_NFC_DEP;
        } else {
@@ -153,8 +232,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
                goto exit;
        }
 
-       target->sel_res = sel_res;
-
        rc = digital_target_found(ddev, target, nfc_proto);
 
 exit: