aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@linux.intel.com>2013-09-19 11:55:27 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-09-24 20:02:23 -0400
commit2c66daecc4092e6049673c281b2e6f0d5e59a94c (patch)
tree6aef21e592f00dc55ef5ad582aaaded57f4676c2 /net/nfc
parent59ee2361c9248f07846f7a6e585768dcce18fb16 (diff)
NFC Digital: Add NFC-A technology support
This adds support for NFC-A technology at 106 kbits/s. The stack can detect tags of type 1 and 2. There is no support for collision detection. Tags can be read and written by using a user space application or a daemon like neard. The flow of polling operations for NFC-A detection is as follow: 1 - The digital stack sends the SENS_REQ command to the NFC device. 2 - The NFC device receives a SENS_RES response from a peer device and passes it to the digital stack. 3 - If the SENS_RES response identifies a type 1 tag, detection ends. NFC core is notified through nfc_targets_found(). 4 - Otherwise, the digital stack sets the cascade level of NFCID1 to CL1 and sends the SDD_REQ command. 5 - The digital stack selects SEL_CMD and SEL_PAR according to the cascade level and sends the SDD_REQ command. 4 - The digital stack receives a SDD_RES response for the cascade level passed in the SDD_REQ command. 5 - The digital stack analyses (part of) NFCID1 and verify BCC. 6 - The digital stack sends the SEL_REQ command with the NFCID1 received in the SDD_RES. 6 - The peer device replies with a SEL_RES response 7 - Detection ends if NFCID1 is complete. NFC core notified of new target by nfc_targets_found(). 8 - If NFCID1 is not complete, the cascade level is incremented (up to and including CL3) and the execution continues at step 5 to get the remaining bytes of NFCID1. Once target detection is done, type 1 and 2 tag commands must be handled by a user space application (i.e neard) through the NFC core. Responses for type 1 tag are returned directly to user space via NFC core. Responses of type 2 commands are handled differently. The digital stack doesn't analyse the type of commands sent through im_transceive() and must differentiate valid responses from error ones. The response process flow is as follow: 1 - If the response length is 16 bytes, it is a valid response of a READ command. the packet is returned to the NFC core through the callback passed to im_transceive(). Processing stops. 2 - If the response is 1 byte long and is a ACK byte (0x0A), it is a valid response of a WRITE command for example. First packet byte is set to 0 for no-error and passed back to the NFC core. Processing stops. 3 - Any other response is treated as an error and -EIO error code is returned to the NFC core through the response callback. Moreover, since the driver can't differentiate success response from a NACK response, the digital stack has to handle CRC calculation. Thus, this patch also adds support for CRC calculation. If the driver doesn't handle it, the digital stack will calculate CRC and will add it to sent frames. CRC will also be checked and removed from received frames. Pointers to the correct CRC calculation functions are stored in the digital stack device structure when a target is detected. This avoids the need to check the current target type for every call to im_transceive() and for every response received from a peer device. Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/Kconfig1
-rw-r--r--net/nfc/digital.h58
-rw-r--r--net/nfc/digital_core.c145
-rw-r--r--net/nfc/digital_technology.c288
4 files changed, 488 insertions, 4 deletions
diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig
index 13e1237e1ea1..4f4d2481325a 100644
--- a/net/nfc/Kconfig
+++ b/net/nfc/Kconfig
@@ -16,6 +16,7 @@ menuconfig NFC
16 16
17config NFC_DIGITAL 17config NFC_DIGITAL
18 depends on NFC 18 depends on NFC
19 select CRC_CCITT
19 tristate "NFC Digital Protocol stack support" 20 tristate "NFC Digital Protocol stack support"
20 default n 21 default n
21 help 22 help
diff --git a/net/nfc/digital.h b/net/nfc/digital.h
index 0a2767098daa..fb5324b792de 100644
--- a/net/nfc/digital.h
+++ b/net/nfc/digital.h
@@ -19,6 +19,8 @@
19#include <net/nfc/nfc.h> 19#include <net/nfc/nfc.h>
20#include <net/nfc/digital.h> 20#include <net/nfc/digital.h>
21 21
22#include <linux/crc-ccitt.h>
23
22#define PR_DBG(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__) 24#define PR_DBG(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__)
23#define PR_ERR(fmt, ...) pr_err("%s: " fmt "\n", __func__, ##__VA_ARGS__) 25#define PR_ERR(fmt, ...) pr_err("%s: " fmt "\n", __func__, ##__VA_ARGS__)
24#define PROTOCOL_ERR(req) pr_err("%s:%d: NFC Digital Protocol error: %s\n", \ 26#define PROTOCOL_ERR(req) pr_err("%s:%d: NFC Digital Protocol error: %s\n", \
@@ -32,6 +34,16 @@
32#define DIGITAL_MAX_HEADER_LEN 7 34#define DIGITAL_MAX_HEADER_LEN 7
33#define DIGITAL_CRC_LEN 2 35#define DIGITAL_CRC_LEN 2
34 36
37#define DIGITAL_DRV_CAPS_IN_CRC(ddev) \
38 ((ddev)->driver_capabilities & NFC_DIGITAL_DRV_CAPS_IN_CRC)
39#define DIGITAL_DRV_CAPS_TG_CRC(ddev) \
40 ((ddev)->driver_capabilities & NFC_DIGITAL_DRV_CAPS_TG_CRC)
41
42struct digital_data_exch {
43 data_exchange_cb_t cb;
44 void *cb_context;
45};
46
35struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev, 47struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
36 unsigned int len); 48 unsigned int len);
37 49
@@ -53,4 +65,50 @@ void digital_poll_next_tech(struct nfc_digital_dev *ddev);
53 65
54int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech); 66int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech);
55 67
68int digital_target_found(struct nfc_digital_dev *ddev,
69 struct nfc_target *target, u8 protocol);
70
71int digital_in_recv_mifare_res(struct sk_buff *resp);
72
73typedef u16 (*crc_func_t)(u16, const u8 *, size_t);
74
75#define CRC_A_INIT 0x6363
76#define CRC_B_INIT 0xFFFF
77
78void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
79 u8 bitwise_inv, u8 msb_first);
80
81static inline void digital_skb_add_crc_a(struct sk_buff *skb)
82{
83 digital_skb_add_crc(skb, crc_ccitt, CRC_A_INIT, 0, 0);
84}
85
86static inline void digital_skb_add_crc_b(struct sk_buff *skb)
87{
88 digital_skb_add_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0);
89}
90
91static inline void digital_skb_add_crc_none(struct sk_buff *skb)
92{
93 return;
94}
95
96int digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
97 u16 crc_init, u8 bitwise_inv, u8 msb_first);
98
99static inline int digital_skb_check_crc_a(struct sk_buff *skb)
100{
101 return digital_skb_check_crc(skb, crc_ccitt, CRC_A_INIT, 0, 0);
102}
103
104static inline int digital_skb_check_crc_b(struct sk_buff *skb)
105{
106 return digital_skb_check_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0);
107}
108
109static inline int digital_skb_check_crc_none(struct sk_buff *skb)
110{
111 return 0;
112}
113
56#endif /* __DIGITAL_H */ 114#endif /* __DIGITAL_H */
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c
index 13abd293ca37..4b3ceb45834b 100644
--- a/net/nfc/digital_core.c
+++ b/net/nfc/digital_core.c
@@ -47,6 +47,51 @@ struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
47 return skb; 47 return skb;
48} 48}
49 49
50void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
51 u8 bitwise_inv, u8 msb_first)
52{
53 u16 crc;
54
55 crc = crc_func(init, skb->data, skb->len);
56
57 if (bitwise_inv)
58 crc = ~crc;
59
60 if (msb_first)
61 crc = __fswab16(crc);
62
63 *skb_put(skb, 1) = crc & 0xFF;
64 *skb_put(skb, 1) = (crc >> 8) & 0xFF;
65}
66
67int digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
68 u16 crc_init, u8 bitwise_inv, u8 msb_first)
69{
70 int rc;
71 u16 crc;
72
73 if (skb->len <= 2)
74 return -EIO;
75
76 crc = crc_func(crc_init, skb->data, skb->len - 2);
77
78 if (bitwise_inv)
79 crc = ~crc;
80
81 if (msb_first)
82 crc = __swab16(crc);
83
84 rc = (skb->data[skb->len - 2] - (crc & 0xFF)) +
85 (skb->data[skb->len - 1] - ((crc >> 8) & 0xFF));
86
87 if (rc)
88 return -EIO;
89
90 skb_trim(skb, skb->len - 2);
91
92 return 0;
93}
94
50static inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on) 95static inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on)
51{ 96{
52 ddev->ops->switch_rf(ddev, on); 97 ddev->ops->switch_rf(ddev, on);
@@ -183,6 +228,62 @@ int digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
183 return rc; 228 return rc;
184} 229}
185 230
231int digital_target_found(struct nfc_digital_dev *ddev,
232 struct nfc_target *target, u8 protocol)
233{
234 int rc;
235 u8 framing;
236 u8 rf_tech;
237 int (*check_crc)(struct sk_buff *skb);
238 void (*add_crc)(struct sk_buff *skb);
239
240 rf_tech = ddev->poll_techs[ddev->poll_tech_index].rf_tech;
241
242 switch (protocol) {
243 case NFC_PROTO_JEWEL:
244 framing = NFC_DIGITAL_FRAMING_NFCA_T1T;
245 check_crc = digital_skb_check_crc_b;
246 add_crc = digital_skb_add_crc_b;
247 break;
248
249 case NFC_PROTO_MIFARE:
250 framing = NFC_DIGITAL_FRAMING_NFCA_T2T;
251 check_crc = digital_skb_check_crc_a;
252 add_crc = digital_skb_add_crc_a;
253 break;
254
255 default:
256 PR_ERR("Invalid protocol %d", protocol);
257 return -EINVAL;
258 }
259
260 PR_DBG("rf_tech=%d, protocol=%d", rf_tech, protocol);
261
262 ddev->curr_rf_tech = rf_tech;
263 ddev->curr_protocol = protocol;
264
265 if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
266 ddev->skb_add_crc = digital_skb_add_crc_none;
267 ddev->skb_check_crc = digital_skb_check_crc_none;
268 } else {
269 ddev->skb_add_crc = add_crc;
270 ddev->skb_check_crc = check_crc;
271 }
272
273 rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, framing);
274 if (rc)
275 return rc;
276
277 target->supported_protocols = (1 << protocol);
278 rc = nfc_targets_found(ddev->nfc_dev, target, 1);
279 if (rc)
280 return rc;
281
282 ddev->poll_tech_count = 0;
283
284 return 0;
285}
286
186void digital_poll_next_tech(struct nfc_digital_dev *ddev) 287void digital_poll_next_tech(struct nfc_digital_dev *ddev)
187{ 288{
188 digital_switch_rf(ddev, 0); 289 digital_switch_rf(ddev, 0);
@@ -363,11 +464,53 @@ static int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb)
363 return -EOPNOTSUPP; 464 return -EOPNOTSUPP;
364} 465}
365 466
467static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg,
468 struct sk_buff *resp)
469{
470 struct digital_data_exch *data_exch = arg;
471 int rc;
472
473 if (IS_ERR(resp)) {
474 rc = PTR_ERR(resp);
475 goto done;
476 }
477
478 if (ddev->curr_protocol == NFC_PROTO_MIFARE)
479 rc = digital_in_recv_mifare_res(resp);
480 else
481 rc = ddev->skb_check_crc(resp);
482
483 if (rc) {
484 kfree_skb(resp);
485 resp = NULL;
486 }
487
488done:
489 data_exch->cb(data_exch->cb_context, resp, rc);
490
491 kfree(data_exch);
492}
493
366static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, 494static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
367 struct sk_buff *skb, data_exchange_cb_t cb, 495 struct sk_buff *skb, data_exchange_cb_t cb,
368 void *cb_context) 496 void *cb_context)
369{ 497{
370 return -EOPNOTSUPP; 498 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
499 struct digital_data_exch *data_exch;
500
501 data_exch = kzalloc(sizeof(struct digital_data_exch), GFP_KERNEL);
502 if (!data_exch) {
503 PR_ERR("Failed to allocate data_exch struct");
504 return -ENOMEM;
505 }
506
507 data_exch->cb = cb;
508 data_exch->cb_context = cb_context;
509
510 ddev->skb_add_crc(skb);
511
512 return digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete,
513 data_exch);
371} 514}
372 515
373static struct nfc_ops digital_nfc_ops = { 516static struct nfc_ops digital_nfc_ops = {
diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c
index 084b0fba5f4d..0cad38001c5f 100644
--- a/net/nfc/digital_technology.c
+++ b/net/nfc/digital_technology.c
@@ -26,13 +26,269 @@
26#define DIGITAL_SDD_RES_CT 0x88 26#define DIGITAL_SDD_RES_CT 0x88
27#define DIGITAL_SDD_RES_LEN 5 27#define DIGITAL_SDD_RES_LEN 5
28 28
29#define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04))
30#define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60))
31
32#define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x000C) == 0x000C)
33#define DIGITAL_SENS_RES_IS_VALID(sens_res) \
34 ((!((sens_res) & 0x1F00) && (((sens_res) & 0x000C) == 0x000C)) || \
35 (((sens_res) & 0x1F00) && ((sens_res) & 0x000C) != 0x000C))
36
37#define DIGITAL_MIFARE_READ_RES_LEN 16
38#define DIGITAL_MIFARE_ACK_RES 0x0A
39
40struct digital_sdd_res {
41 u8 nfcid1[4];
42 u8 bcc;
43} __packed;
44
45struct digital_sel_req {
46 u8 sel_cmd;
47 u8 b2;
48 u8 nfcid1[4];
49 u8 bcc;
50} __packed;
51
52static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev,
53 struct nfc_target *target);
54
55static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
56 struct sk_buff *resp)
57{
58 struct nfc_target *target = arg;
59 int rc;
60 u8 sel_res;
61 u8 nfc_proto;
62
63 if (IS_ERR(resp)) {
64 rc = PTR_ERR(resp);
65 resp = NULL;
66 goto exit;
67 }
68
69 if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
70 rc = digital_skb_check_crc_a(resp);
71 if (rc) {
72 PROTOCOL_ERR("4.4.1.3");
73 goto exit;
74 }
75 }
76
77 if (!resp->len) {
78 rc = -EIO;
79 goto exit;
80 }
81
82 sel_res = resp->data[0];
83
84 if (!DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res)) {
85 rc = digital_in_send_sdd_req(ddev, target);
86 if (rc)
87 goto exit;
88
89 goto exit_free_skb;
90 }
91
92 if (DIGITAL_SEL_RES_IS_T2T(sel_res)) {
93 nfc_proto = NFC_PROTO_MIFARE;
94 } else {
95 rc = -EOPNOTSUPP;
96 goto exit;
97 }
98
99 target->sel_res = sel_res;
100
101 rc = digital_target_found(ddev, target, nfc_proto);
102
103exit:
104 kfree(target);
105
106exit_free_skb:
107 dev_kfree_skb(resp);
108
109 if (rc)
110 digital_poll_next_tech(ddev);
111}
112
113static int digital_in_send_sel_req(struct nfc_digital_dev *ddev,
114 struct nfc_target *target,
115 struct digital_sdd_res *sdd_res)
116{
117 struct sk_buff *skb;
118 struct digital_sel_req *sel_req;
119 u8 sel_cmd;
120 int rc;
121
122 skb = digital_skb_alloc(ddev, sizeof(struct digital_sel_req));
123 if (!skb)
124 return -ENOMEM;
125
126 skb_put(skb, sizeof(struct digital_sel_req));
127 sel_req = (struct digital_sel_req *)skb->data;
128
129 if (target->nfcid1_len <= 4)
130 sel_cmd = DIGITAL_CMD_SEL_REQ_CL1;
131 else if (target->nfcid1_len < 10)
132 sel_cmd = DIGITAL_CMD_SEL_REQ_CL2;
133 else
134 sel_cmd = DIGITAL_CMD_SEL_REQ_CL3;
135
136 sel_req->sel_cmd = sel_cmd;
137 sel_req->b2 = 0x70;
138 memcpy(sel_req->nfcid1, sdd_res->nfcid1, 4);
139 sel_req->bcc = sdd_res->bcc;
140
141 if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
142 rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
143 NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A);
144 if (rc)
145 goto exit;
146 } else {
147 digital_skb_add_crc_a(skb);
148 }
149
150 rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sel_res,
151 target);
152exit:
153 if (rc)
154 kfree_skb(skb);
155
156 return rc;
157}
158
159static void digital_in_recv_sdd_res(struct nfc_digital_dev *ddev, void *arg,
160 struct sk_buff *resp)
161{
162 struct nfc_target *target = arg;
163 struct digital_sdd_res *sdd_res;
164 int rc;
165 u8 offset, size;
166 u8 i, bcc;
167
168 if (IS_ERR(resp)) {
169 rc = PTR_ERR(resp);
170 resp = NULL;
171 goto exit;
172 }
173
174 if (resp->len < DIGITAL_SDD_RES_LEN) {
175 PROTOCOL_ERR("4.7.2.8");
176 rc = -EINVAL;
177 goto exit;
178 }
179
180 sdd_res = (struct digital_sdd_res *)resp->data;
181
182 for (i = 0, bcc = 0; i < 4; i++)
183 bcc ^= sdd_res->nfcid1[i];
184
185 if (bcc != sdd_res->bcc) {
186 PROTOCOL_ERR("4.7.2.6");
187 rc = -EINVAL;
188 goto exit;
189 }
190
191 if (sdd_res->nfcid1[0] == DIGITAL_SDD_RES_CT) {
192 offset = 1;
193 size = 3;
194 } else {
195 offset = 0;
196 size = 4;
197 }
198
199 memcpy(target->nfcid1 + target->nfcid1_len, sdd_res->nfcid1 + offset,
200 size);
201 target->nfcid1_len += size;
202
203 rc = digital_in_send_sel_req(ddev, target, sdd_res);
204
205exit:
206 dev_kfree_skb(resp);
207
208 if (rc) {
209 kfree(target);
210 digital_poll_next_tech(ddev);
211 }
212}
213
214static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev,
215 struct nfc_target *target)
216{
217 int rc;
218 struct sk_buff *skb;
219 u8 sel_cmd;
220
221 rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
222 NFC_DIGITAL_FRAMING_NFCA_STANDARD);
223 if (rc)
224 return rc;
225
226 skb = digital_skb_alloc(ddev, 2);
227 if (!skb) {
228 PR_ERR("alloc_skb failed");
229 return -ENOMEM;
230 }
231
232 if (target->nfcid1_len == 0)
233 sel_cmd = DIGITAL_CMD_SEL_REQ_CL1;
234 else if (target->nfcid1_len == 3)
235 sel_cmd = DIGITAL_CMD_SEL_REQ_CL2;
236 else
237 sel_cmd = DIGITAL_CMD_SEL_REQ_CL3;
238
239 *skb_put(skb, sizeof(u8)) = sel_cmd;
240 *skb_put(skb, sizeof(u8)) = DIGITAL_SDD_REQ_SEL_PAR;
241
242 return digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sdd_res,
243 target);
244}
245
29static void digital_in_recv_sens_res(struct nfc_digital_dev *ddev, void *arg, 246static void digital_in_recv_sens_res(struct nfc_digital_dev *ddev, void *arg,
30 struct sk_buff *resp) 247 struct sk_buff *resp)
31{ 248{
32 if (!IS_ERR(resp)) 249 struct nfc_target *target = NULL;
33 dev_kfree_skb(resp); 250 u16 sens_res;
251 int rc;
252
253 if (IS_ERR(resp)) {
254 rc = PTR_ERR(resp);
255 resp = NULL;
256 goto exit;
257 }
258
259 if (resp->len < sizeof(u16)) {
260 rc = -EIO;
261 goto exit;
262 }
263
264 target = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
265 if (!target) {
266 rc = -ENOMEM;
267 goto exit;
268 }
269
270 memcpy(&target->sens_res, resp->data, sizeof(u16));
34 271
35 digital_poll_next_tech(ddev); 272 sens_res = be16_to_cpu(target->sens_res);
273
274 if (!DIGITAL_SENS_RES_IS_VALID(sens_res)) {
275 PROTOCOL_ERR("4.6.3.3");
276 rc = -EINVAL;
277 goto exit;
278 }
279
280 if (DIGITAL_SENS_RES_IS_T1T(sens_res))
281 rc = digital_target_found(ddev, target, NFC_PROTO_JEWEL);
282 else
283 rc = digital_in_send_sdd_req(ddev, target);
284
285exit:
286 dev_kfree_skb(resp);
287
288 if (rc) {
289 kfree(target);
290 digital_poll_next_tech(ddev);
291 }
36} 292}
37 293
38int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech) 294int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech)
@@ -62,3 +318,29 @@ int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech)
62 318
63 return rc; 319 return rc;
64} 320}
321
322int digital_in_recv_mifare_res(struct sk_buff *resp)
323{
324 /* Successful READ command response is 16 data bytes + 2 CRC bytes long.
325 * Since the driver can't differentiate a ACK/NACK response from a valid
326 * READ response, the CRC calculation must be handled at digital level
327 * even if the driver supports it for this technology.
328 */
329 if (resp->len == DIGITAL_MIFARE_READ_RES_LEN + DIGITAL_CRC_LEN) {
330 if (digital_skb_check_crc_a(resp)) {
331 PROTOCOL_ERR("9.4.1.2");
332 return -EIO;
333 }
334
335 return 0;
336 }
337
338 /* ACK response (i.e. successful WRITE). */
339 if (resp->len == 1 && resp->data[0] == DIGITAL_MIFARE_ACK_RES) {
340 resp->data[0] = 0;
341 return 0;
342 }
343
344 /* NACK and any other responses are treated as error. */
345 return -EIO;
346}