NFC: digital: Add Inititor-side PSL support
authorMark A. Greer <mgreer@animalcreek.com>
Wed, 23 Jul 2014 03:18:01 +0000 (20:18 -0700)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 31 Aug 2014 20:15:37 +0000 (22:15 +0200)
In order to operate at the fasted bit rate
possible, add initiator-side support for
PSL REQ while in P2P mode.  The PSL REQ
will switch the RF technology to 424F
whenever possible.

Reviewed-by: Thierry Escande <thierry.escande@linux.intel.com>
Tested-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
net/nfc/digital_dep.c

index e1638dab076da4688057889299244125b42419bb..b60aa35c074f5220f0b939b347881cab8e6c9db8 100644 (file)
@@ -33,6 +33,8 @@
 #define DIGITAL_ATR_REQ_MAX_SIZE 64
 
 #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30
+#define DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B \
+                               (DIGITAL_LR_BITS_PAYLOAD_SIZE_254B >> 4)
 #define DIGITAL_GB_BIT 0x02
 
 #define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0)
@@ -127,6 +129,98 @@ static int digital_skb_pull_dep_sod(struct nfc_digital_dev *ddev,
        return 0;
 }
 
+static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg,
+                                   struct sk_buff *resp)
+{
+       struct nfc_target *target = arg;
+       struct digital_psl_res *psl_res;
+       int rc;
+
+       if (IS_ERR(resp)) {
+               rc = PTR_ERR(resp);
+               resp = NULL;
+               goto exit;
+       }
+
+       rc = ddev->skb_check_crc(resp);
+       if (rc) {
+               PROTOCOL_ERR("14.4.1.6");
+               goto exit;
+       }
+
+       rc = digital_skb_pull_dep_sod(ddev, resp);
+       if (rc) {
+               PROTOCOL_ERR("14.4.1.2");
+               goto exit;
+       }
+
+       psl_res = (struct digital_psl_res *)resp->data;
+
+       if ((resp->len != sizeof(*psl_res)) ||
+           (psl_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN) ||
+           (psl_res->cmd != DIGITAL_CMD_PSL_RES)) {
+               rc = -EIO;
+               goto exit;
+       }
+
+       rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
+                                    NFC_DIGITAL_RF_TECH_424F);
+       if (rc)
+               goto exit;
+
+       rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
+                                    NFC_DIGITAL_FRAMING_NFCF_NFC_DEP);
+       if (rc)
+               goto exit;
+
+       if (!DIGITAL_DRV_CAPS_IN_CRC(ddev) &&
+           (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A)) {
+               ddev->skb_add_crc = digital_skb_add_crc_f;
+               ddev->skb_check_crc = digital_skb_check_crc_f;
+       }
+
+       ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_424F;
+
+       nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE,
+                          NFC_RF_INITIATOR);
+
+       ddev->curr_nfc_dep_pni = 0;
+
+exit:
+       dev_kfree_skb(resp);
+
+       if (rc)
+               ddev->curr_protocol = 0;
+}
+
+static int digital_in_send_psl_req(struct nfc_digital_dev *ddev,
+                                  struct nfc_target *target)
+{
+       struct sk_buff *skb;
+       struct digital_psl_req *psl_req;
+
+       skb = digital_skb_alloc(ddev, sizeof(*psl_req));
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, sizeof(*psl_req));
+
+       psl_req = (struct digital_psl_req *)skb->data;
+
+       psl_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
+       psl_req->cmd = DIGITAL_CMD_PSL_REQ;
+       psl_req->did = 0;
+       psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */
+       psl_req->fsl = DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B;
+
+       digital_skb_push_dep_sod(ddev, skb);
+
+       ddev->skb_add_crc(skb);
+
+       return digital_in_send_cmd(ddev, skb, 500, digital_in_recv_psl_res,
+                                  target);
+}
+
 static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg,
                                 struct sk_buff *resp)
 {
@@ -166,6 +260,13 @@ static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg,
        if (rc)
                goto exit;
 
+       if ((ddev->protocols & NFC_PROTO_FELICA_MASK) &&
+           (ddev->curr_rf_tech != NFC_DIGITAL_RF_TECH_424F)) {
+               rc = digital_in_send_psl_req(ddev, target);
+               if (!rc)
+                       goto exit;
+       }
+
        rc = nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE,
                                NFC_RF_INITIATOR);
 
This page took 0.026022 seconds and 5 git commands to generate.