Commit 12e3d241 authored by Thierry Escande's avatar Thierry Escande Committed by Samuel Ortiz
Browse files

NFC: digital: Add poll support for type 4A tag platform



This adds support for ATS request and response handling for type 4A tag
activation.

Signed-off-by: default avatarThierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent d3815ea9
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
};
+7 −0
Original line number Diff line number Diff line
@@ -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;
+79 −2
Original line number Diff line number Diff line
@@ -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)
@@ -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;
@@ -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: