Skip to content

Commit

Permalink
NFC: digital: Add poll support for type 4A tag platform
Browse files Browse the repository at this point in the history
This adds support for ATS request and response handling for type 4A tag
activation.

Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
  • Loading branch information
Thierry Escande authored and Samuel Ortiz committed Feb 16, 2014
1 parent d3815ea commit 12e3d24
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 2 deletions.
3 changes: 3 additions & 0 deletions include/net/nfc/digital.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
};
Expand Down
7 changes: 7 additions & 0 deletions net/nfc/digital_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
81 changes: 79 additions & 2 deletions net/nfc/digital_technology.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -60,6 +61,16 @@
#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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -144,17 +212,26 @@ 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 {
rc = -EOPNOTSUPP;
goto exit;
}

target->sel_res = sel_res;

rc = digital_target_found(ddev, target, nfc_proto);

exit:
Expand Down

0 comments on commit 12e3d24

Please sign in to comment.