diff options
author | Thierry Escande <thierry.escande@linux.intel.com> | 2014-01-26 18:31:31 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-02-16 17:49:54 -0500 |
commit | 12e3d241e42956da168fd499347855af799f62fb (patch) | |
tree | 8308212156ce23e3778c7745d58bc8a9583dca76 /net | |
parent | d3815ea95c67e62a2c651e7b5b4e08e95a4cbb13 (diff) |
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: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/digital_core.c | 7 | ||||
-rw-r--r-- | net/nfc/digital_technology.c | 81 |
2 files changed, 86 insertions, 2 deletions
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index 48906ca60540..e1f240266adf 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c | |||
@@ -337,6 +337,11 @@ int digital_target_found(struct nfc_digital_dev *ddev, | |||
337 | framing = NFC_DIGITAL_FRAMING_ISO15693_TVT; | 337 | framing = NFC_DIGITAL_FRAMING_ISO15693_TVT; |
338 | check_crc = digital_skb_check_crc_b; | 338 | check_crc = digital_skb_check_crc_b; |
339 | add_crc = digital_skb_add_crc_b; | 339 | add_crc = digital_skb_add_crc_b; |
340 | |||
341 | case NFC_PROTO_ISO14443: | ||
342 | framing = NFC_DIGITAL_FRAMING_NFCA_T4T; | ||
343 | check_crc = digital_skb_check_crc_a; | ||
344 | add_crc = digital_skb_add_crc_a; | ||
340 | break; | 345 | break; |
341 | 346 | ||
342 | default: | 347 | default: |
@@ -714,6 +719,8 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, | |||
714 | ddev->protocols |= NFC_PROTO_NFC_DEP_MASK; | 719 | ddev->protocols |= NFC_PROTO_NFC_DEP_MASK; |
715 | if (supported_protocols & NFC_PROTO_ISO15693_MASK) | 720 | if (supported_protocols & NFC_PROTO_ISO15693_MASK) |
716 | ddev->protocols |= NFC_PROTO_ISO15693_MASK; | 721 | ddev->protocols |= NFC_PROTO_ISO15693_MASK; |
722 | if (supported_protocols & NFC_PROTO_ISO14443_MASK) | ||
723 | ddev->protocols |= NFC_PROTO_ISO14443_MASK; | ||
717 | 724 | ||
718 | ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN; | 725 | ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN; |
719 | ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN; | 726 | ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN; |
diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index 97d3f602fc06..6649d9461dff 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04)) | 31 | #define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04)) |
32 | #define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60)) | 32 | #define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60)) |
33 | #define DIGITAL_SEL_RES_IS_T4T(sel_res) ((sel_res) & 0x20) | ||
33 | #define DIGITAL_SEL_RES_IS_NFC_DEP(sel_res) ((sel_res) & 0x40) | 34 | #define DIGITAL_SEL_RES_IS_NFC_DEP(sel_res) ((sel_res) & 0x40) |
34 | 35 | ||
35 | #define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x0C00) == 0x0C00) | 36 | #define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x0C00) == 0x0C00) |
@@ -60,6 +61,16 @@ | |||
60 | #define DIGITAL_ISO15693_RES_IS_VALID(flags) \ | 61 | #define DIGITAL_ISO15693_RES_IS_VALID(flags) \ |
61 | (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) | 62 | (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) |
62 | 63 | ||
64 | static const u8 digital_ats_fsc[] = { | ||
65 | 16, 24, 32, 40, 48, 64, 96, 128, | ||
66 | }; | ||
67 | |||
68 | #define DIGITAL_ATS_FSCI(t0) ((t0) & 0x0F) | ||
69 | #define DIGITAL_ATS_MAX_FSC 256 | ||
70 | |||
71 | #define DIGITAL_RATS_BYTE1 0xE0 | ||
72 | #define DIGITAL_RATS_PARAM 0x80 | ||
73 | |||
63 | struct digital_sdd_res { | 74 | struct digital_sdd_res { |
64 | u8 nfcid1[4]; | 75 | u8 nfcid1[4]; |
65 | u8 bcc; | 76 | u8 bcc; |
@@ -107,6 +118,63 @@ struct digital_iso15693_inv_res { | |||
107 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, | 118 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, |
108 | struct nfc_target *target); | 119 | struct nfc_target *target); |
109 | 120 | ||
121 | static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, | ||
122 | struct sk_buff *resp) | ||
123 | { | ||
124 | struct nfc_target *target = arg; | ||
125 | u8 fsdi; | ||
126 | int rc; | ||
127 | |||
128 | if (IS_ERR(resp)) { | ||
129 | rc = PTR_ERR(resp); | ||
130 | resp = NULL; | ||
131 | goto exit; | ||
132 | } | ||
133 | |||
134 | if (resp->len < 2) { | ||
135 | rc = -EIO; | ||
136 | goto exit; | ||
137 | } | ||
138 | |||
139 | fsdi = DIGITAL_ATS_FSCI(resp->data[1]); | ||
140 | if (fsdi >= 8) | ||
141 | ddev->target_fsc = DIGITAL_ATS_MAX_FSC; | ||
142 | else | ||
143 | ddev->target_fsc = digital_ats_fsc[fsdi]; | ||
144 | |||
145 | ddev->curr_nfc_dep_pni = 0; | ||
146 | |||
147 | rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443); | ||
148 | |||
149 | exit: | ||
150 | dev_kfree_skb(resp); | ||
151 | kfree(target); | ||
152 | |||
153 | if (rc) | ||
154 | digital_poll_next_tech(ddev); | ||
155 | } | ||
156 | |||
157 | static int digital_in_send_rats(struct nfc_digital_dev *ddev, | ||
158 | struct nfc_target *target) | ||
159 | { | ||
160 | int rc; | ||
161 | struct sk_buff *skb; | ||
162 | |||
163 | skb = digital_skb_alloc(ddev, 2); | ||
164 | if (!skb) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | *skb_put(skb, 1) = DIGITAL_RATS_BYTE1; | ||
168 | *skb_put(skb, 1) = DIGITAL_RATS_PARAM; | ||
169 | |||
170 | rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_ats, | ||
171 | target); | ||
172 | if (rc) | ||
173 | kfree_skb(skb); | ||
174 | |||
175 | return rc; | ||
176 | } | ||
177 | |||
110 | static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | 178 | static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, |
111 | struct sk_buff *resp) | 179 | struct sk_buff *resp) |
112 | { | 180 | { |
@@ -144,8 +212,19 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | |||
144 | goto exit_free_skb; | 212 | goto exit_free_skb; |
145 | } | 213 | } |
146 | 214 | ||
215 | target->sel_res = sel_res; | ||
216 | |||
147 | if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { | 217 | if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { |
148 | nfc_proto = NFC_PROTO_MIFARE; | 218 | nfc_proto = NFC_PROTO_MIFARE; |
219 | } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { | ||
220 | rc = digital_in_send_rats(ddev, target); | ||
221 | if (rc) | ||
222 | goto exit; | ||
223 | /* | ||
224 | * Skip target_found and don't free it for now. This will be | ||
225 | * done when receiving the ATS | ||
226 | */ | ||
227 | goto exit_free_skb; | ||
149 | } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { | 228 | } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { |
150 | nfc_proto = NFC_PROTO_NFC_DEP; | 229 | nfc_proto = NFC_PROTO_NFC_DEP; |
151 | } else { | 230 | } else { |
@@ -153,8 +232,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | |||
153 | goto exit; | 232 | goto exit; |
154 | } | 233 | } |
155 | 234 | ||
156 | target->sel_res = sel_res; | ||
157 | |||
158 | rc = digital_target_found(ddev, target, nfc_proto); | 235 | rc = digital_target_found(ddev, target, nfc_proto); |
159 | 236 | ||
160 | exit: | 237 | exit: |