diff options
author | Thierry Escande <thierry.escande@linux.intel.com> | 2014-01-27 00:31:32 +0100 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-02-16 23:49:54 +0100 |
commit | c813007f9ffb0b6e9f3dc43bfd9e28806aa57e5d (patch) | |
tree | 1a030aa83175313551eecfd7f23d08797481837b /net/nfc/digital_technology.c | |
parent | 12e3d241e42956da168fd499347855af799f62fb (diff) |
NFC: digital: Add ISO-DEP support for data exchange
When a type 4A target is activated, this change adds the ISO-DEP SoD
when sending frames and removes it when receiving responses. Chaining
is not supported so sent frames are rejected if they exceed remote FSC
bytes.
Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc/digital_technology.c')
-rw-r--r-- | net/nfc/digital_technology.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index 6649d9461dff..278c3fed27e0 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c @@ -61,6 +61,15 @@ #define DIGITAL_ISO15693_RES_IS_VALID(flags) \ (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) +#define DIGITAL_ISO_DEP_I_PCB 0x02 +#define DIGITAL_ISO_DEP_PNI(pni) ((pni) & 0x01) + +#define DIGITAL_ISO_DEP_PCB_TYPE(pcb) ((pcb) & 0xC0) + +#define DIGITAL_ISO_DEP_I_BLOCK 0x00 + +#define DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb) ((pcb) & 0x08) + static const u8 digital_ats_fsc[] = { 16, 24, 32, 40, 48, 64, 96, 128, }; @@ -118,6 +127,54 @@ struct digital_iso15693_inv_res { static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, struct nfc_target *target); +int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, + struct sk_buff *skb) +{ + u8 pcb; + u8 block_type; + + if (skb->len < 1) + return -EIO; + + pcb = *skb->data; + block_type = DIGITAL_ISO_DEP_PCB_TYPE(pcb); + + /* No support fo R-block nor S-block */ + if (block_type != DIGITAL_ISO_DEP_I_BLOCK) { + pr_err("ISO_DEP R-block and S-block not supported\n"); + return -EIO; + } + + if (DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb)) { + pr_err("DID field in ISO_DEP PCB not supported\n"); + return -EIO; + } + + skb_pull(skb, 1); + + return 0; +} + +int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, + struct sk_buff *skb) +{ + /* + * Chaining not supported so skb->len + 1 PCB byte + 2 CRC bytes must + * not be greater than remote FSC + */ + if (skb->len + 3 > ddev->target_fsc) + return -EIO; + + skb_push(skb, 1); + + *skb->data = DIGITAL_ISO_DEP_I_PCB | ddev->curr_nfc_dep_pni; + + ddev->curr_nfc_dep_pni = + DIGITAL_ISO_DEP_PNI(ddev->curr_nfc_dep_pni + 1); + + return 0; +} + static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, struct sk_buff *resp) { |