diff options
author | Thierry Escande <thierry.escande@linux.intel.com> | 2013-09-19 11:55:28 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-09-24 20:02:25 -0400 |
commit | 8c0695e4998dd268ff2a05951961247b7e015651 (patch) | |
tree | 86087518d7435dbe788647ee04be2b460bab0ee8 | |
parent | 2c66daecc4092e6049673c281b2e6f0d5e59a94c (diff) |
NFC Digital: Add NFC-F technology support
This adds polling support for NFC-F technology at 212 kbits/s and 424
kbits/s. A user space application like neard can send type 3 tag
commands through the NFC core.
Process flow for NFC-F detection is as follow:
1 - The digital stack sends the SENSF_REQ command to the NFC device.
2 - A peer device replies with a SENSF_RES response.
3 - The digital stack notifies the NFC core of the presence of a
target in the operation field and passes the target NFCID2.
This also adds support for CRC calculation of type CRC-F. The CRC
calculation is handled by the digital stack if the NFC device doesn't
support it.
Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | net/nfc/Kconfig | 1 | ||||
-rw-r--r-- | net/nfc/digital.h | 13 | ||||
-rw-r--r-- | net/nfc/digital_core.c | 18 | ||||
-rw-r--r-- | net/nfc/digital_technology.c | 121 |
4 files changed, 153 insertions, 0 deletions
diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig index 4f4d2481325a..6e0fa0cce198 100644 --- a/net/nfc/Kconfig +++ b/net/nfc/Kconfig | |||
@@ -17,6 +17,7 @@ menuconfig NFC | |||
17 | config NFC_DIGITAL | 17 | config NFC_DIGITAL |
18 | depends on NFC | 18 | depends on NFC |
19 | select CRC_CCITT | 19 | select CRC_CCITT |
20 | select CRC_ITU_T | ||
20 | tristate "NFC Digital Protocol stack support" | 21 | tristate "NFC Digital Protocol stack support" |
21 | default n | 22 | default n |
22 | help | 23 | help |
diff --git a/net/nfc/digital.h b/net/nfc/digital.h index fb5324b792de..85bc74c988f8 100644 --- a/net/nfc/digital.h +++ b/net/nfc/digital.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <net/nfc/digital.h> | 20 | #include <net/nfc/digital.h> |
21 | 21 | ||
22 | #include <linux/crc-ccitt.h> | 22 | #include <linux/crc-ccitt.h> |
23 | #include <linux/crc-itu-t.h> | ||
23 | 24 | ||
24 | #define PR_DBG(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__) | 25 | #define PR_DBG(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__) |
25 | #define PR_ERR(fmt, ...) pr_err("%s: " fmt "\n", __func__, ##__VA_ARGS__) | 26 | #define PR_ERR(fmt, ...) pr_err("%s: " fmt "\n", __func__, ##__VA_ARGS__) |
@@ -64,6 +65,7 @@ static inline int digital_in_send_cmd(struct nfc_digital_dev *ddev, | |||
64 | void digital_poll_next_tech(struct nfc_digital_dev *ddev); | 65 | void digital_poll_next_tech(struct nfc_digital_dev *ddev); |
65 | 66 | ||
66 | int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech); | 67 | int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech); |
68 | int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech); | ||
67 | 69 | ||
68 | int digital_target_found(struct nfc_digital_dev *ddev, | 70 | int digital_target_found(struct nfc_digital_dev *ddev, |
69 | struct nfc_target *target, u8 protocol); | 71 | struct nfc_target *target, u8 protocol); |
@@ -74,6 +76,7 @@ typedef u16 (*crc_func_t)(u16, const u8 *, size_t); | |||
74 | 76 | ||
75 | #define CRC_A_INIT 0x6363 | 77 | #define CRC_A_INIT 0x6363 |
76 | #define CRC_B_INIT 0xFFFF | 78 | #define CRC_B_INIT 0xFFFF |
79 | #define CRC_F_INIT 0x0000 | ||
77 | 80 | ||
78 | void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init, | 81 | void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init, |
79 | u8 bitwise_inv, u8 msb_first); | 82 | u8 bitwise_inv, u8 msb_first); |
@@ -88,6 +91,11 @@ static inline void digital_skb_add_crc_b(struct sk_buff *skb) | |||
88 | digital_skb_add_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0); | 91 | digital_skb_add_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0); |
89 | } | 92 | } |
90 | 93 | ||
94 | static inline void digital_skb_add_crc_f(struct sk_buff *skb) | ||
95 | { | ||
96 | digital_skb_add_crc(skb, crc_itu_t, CRC_F_INIT, 0, 1); | ||
97 | } | ||
98 | |||
91 | static inline void digital_skb_add_crc_none(struct sk_buff *skb) | 99 | static inline void digital_skb_add_crc_none(struct sk_buff *skb) |
92 | { | 100 | { |
93 | return; | 101 | return; |
@@ -106,6 +114,11 @@ static inline int digital_skb_check_crc_b(struct sk_buff *skb) | |||
106 | return digital_skb_check_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0); | 114 | return digital_skb_check_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0); |
107 | } | 115 | } |
108 | 116 | ||
117 | static inline int digital_skb_check_crc_f(struct sk_buff *skb) | ||
118 | { | ||
119 | return digital_skb_check_crc(skb, crc_itu_t, CRC_F_INIT, 0, 1); | ||
120 | } | ||
121 | |||
109 | static inline int digital_skb_check_crc_none(struct sk_buff *skb) | 122 | static inline int digital_skb_check_crc_none(struct sk_buff *skb) |
110 | { | 123 | { |
111 | return 0; | 124 | return 0; |
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index 4b3ceb45834b..25e5bcb946e0 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #define DIGITAL_PROTO_NFCA_RF_TECH \ | 20 | #define DIGITAL_PROTO_NFCA_RF_TECH \ |
21 | (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK) | 21 | (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK) |
22 | 22 | ||
23 | #define DIGITAL_PROTO_NFCF_RF_TECH (NFC_PROTO_FELICA_MASK) | ||
24 | |||
23 | struct digital_cmd { | 25 | struct digital_cmd { |
24 | struct list_head queue; | 26 | struct list_head queue; |
25 | 27 | ||
@@ -252,6 +254,12 @@ int digital_target_found(struct nfc_digital_dev *ddev, | |||
252 | add_crc = digital_skb_add_crc_a; | 254 | add_crc = digital_skb_add_crc_a; |
253 | break; | 255 | break; |
254 | 256 | ||
257 | case NFC_PROTO_FELICA: | ||
258 | framing = NFC_DIGITAL_FRAMING_NFCF_T3T; | ||
259 | check_crc = digital_skb_check_crc_f; | ||
260 | add_crc = digital_skb_add_crc_f; | ||
261 | break; | ||
262 | |||
255 | default: | 263 | default: |
256 | PR_ERR("Invalid protocol %d", protocol); | 264 | PR_ERR("Invalid protocol %d", protocol); |
257 | return -EINVAL; | 265 | return -EINVAL; |
@@ -383,6 +391,14 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, | |||
383 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, | 391 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, |
384 | digital_in_send_sens_req); | 392 | digital_in_send_sens_req); |
385 | 393 | ||
394 | if (im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) { | ||
395 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F, | ||
396 | digital_in_send_sensf_req); | ||
397 | |||
398 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F, | ||
399 | digital_in_send_sensf_req); | ||
400 | } | ||
401 | |||
386 | if (!ddev->poll_tech_count) { | 402 | if (!ddev->poll_tech_count) { |
387 | PR_ERR("Unsupported protocols: im=0x%x, tm=0x%x", | 403 | PR_ERR("Unsupported protocols: im=0x%x, tm=0x%x", |
388 | matching_im_protocols, matching_tm_protocols); | 404 | matching_im_protocols, matching_tm_protocols); |
@@ -560,6 +576,8 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, | |||
560 | ddev->protocols |= NFC_PROTO_JEWEL_MASK; | 576 | ddev->protocols |= NFC_PROTO_JEWEL_MASK; |
561 | if (supported_protocols & NFC_PROTO_MIFARE_MASK) | 577 | if (supported_protocols & NFC_PROTO_MIFARE_MASK) |
562 | ddev->protocols |= NFC_PROTO_MIFARE_MASK; | 578 | ddev->protocols |= NFC_PROTO_MIFARE_MASK; |
579 | if (supported_protocols & NFC_PROTO_FELICA_MASK) | ||
580 | ddev->protocols |= NFC_PROTO_FELICA_MASK; | ||
563 | 581 | ||
564 | ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN; | 582 | ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN; |
565 | ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN; | 583 | ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN; |
diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index 0cad38001c5f..bfe5ae17909e 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c | |||
@@ -37,6 +37,17 @@ | |||
37 | #define DIGITAL_MIFARE_READ_RES_LEN 16 | 37 | #define DIGITAL_MIFARE_READ_RES_LEN 16 |
38 | #define DIGITAL_MIFARE_ACK_RES 0x0A | 38 | #define DIGITAL_MIFARE_ACK_RES 0x0A |
39 | 39 | ||
40 | #define DIGITAL_CMD_SENSF_REQ 0x00 | ||
41 | #define DIGITAL_CMD_SENSF_RES 0x01 | ||
42 | |||
43 | #define DIGITAL_SENSF_RES_MIN_LENGTH 17 | ||
44 | #define DIGITAL_SENSF_RES_RD_AP_B1 0x00 | ||
45 | #define DIGITAL_SENSF_RES_RD_AP_B2 0x8F | ||
46 | |||
47 | #define DIGITAL_SENSF_REQ_RC_NONE 0 | ||
48 | #define DIGITAL_SENSF_REQ_RC_SC 1 | ||
49 | #define DIGITAL_SENSF_REQ_RC_AP 2 | ||
50 | |||
40 | struct digital_sdd_res { | 51 | struct digital_sdd_res { |
41 | u8 nfcid1[4]; | 52 | u8 nfcid1[4]; |
42 | u8 bcc; | 53 | u8 bcc; |
@@ -49,6 +60,25 @@ struct digital_sel_req { | |||
49 | u8 bcc; | 60 | u8 bcc; |
50 | } __packed; | 61 | } __packed; |
51 | 62 | ||
63 | struct digital_sensf_req { | ||
64 | u8 cmd; | ||
65 | u8 sc1; | ||
66 | u8 sc2; | ||
67 | u8 rc; | ||
68 | u8 tsn; | ||
69 | } __packed; | ||
70 | |||
71 | struct digital_sensf_res { | ||
72 | u8 cmd; | ||
73 | u8 nfcid2[8]; | ||
74 | u8 pad0[2]; | ||
75 | u8 pad1[3]; | ||
76 | u8 mrti_check; | ||
77 | u8 mrti_update; | ||
78 | u8 pad2; | ||
79 | u8 rd[2]; | ||
80 | } __packed; | ||
81 | |||
52 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, | 82 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, |
53 | struct nfc_target *target); | 83 | struct nfc_target *target); |
54 | 84 | ||
@@ -344,3 +374,94 @@ int digital_in_recv_mifare_res(struct sk_buff *resp) | |||
344 | /* NACK and any other responses are treated as error. */ | 374 | /* NACK and any other responses are treated as error. */ |
345 | return -EIO; | 375 | return -EIO; |
346 | } | 376 | } |
377 | |||
378 | static void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg, | ||
379 | struct sk_buff *resp) | ||
380 | { | ||
381 | int rc; | ||
382 | struct nfc_target target; | ||
383 | struct digital_sensf_res *sensf_res; | ||
384 | |||
385 | if (IS_ERR(resp)) { | ||
386 | rc = PTR_ERR(resp); | ||
387 | resp = NULL; | ||
388 | goto exit; | ||
389 | } | ||
390 | |||
391 | if (resp->len < DIGITAL_SENSF_RES_MIN_LENGTH) { | ||
392 | rc = -EIO; | ||
393 | goto exit; | ||
394 | } | ||
395 | |||
396 | if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) { | ||
397 | rc = digital_skb_check_crc_f(resp); | ||
398 | if (rc) { | ||
399 | PROTOCOL_ERR("6.4.1.8"); | ||
400 | goto exit; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | skb_pull(resp, 1); | ||
405 | |||
406 | memset(&target, 0, sizeof(struct nfc_target)); | ||
407 | |||
408 | sensf_res = (struct digital_sensf_res *)resp->data; | ||
409 | |||
410 | memcpy(target.sensf_res, sensf_res, resp->len); | ||
411 | target.sensf_res_len = resp->len; | ||
412 | |||
413 | memcpy(target.nfcid2, sensf_res->nfcid2, NFC_NFCID2_MAXSIZE); | ||
414 | target.nfcid2_len = NFC_NFCID2_MAXSIZE; | ||
415 | |||
416 | rc = digital_target_found(ddev, &target, NFC_PROTO_FELICA); | ||
417 | |||
418 | exit: | ||
419 | dev_kfree_skb(resp); | ||
420 | |||
421 | if (rc) | ||
422 | digital_poll_next_tech(ddev); | ||
423 | } | ||
424 | |||
425 | int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech) | ||
426 | { | ||
427 | struct digital_sensf_req *sensf_req; | ||
428 | struct sk_buff *skb; | ||
429 | int rc; | ||
430 | u8 size; | ||
431 | |||
432 | rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); | ||
433 | if (rc) | ||
434 | return rc; | ||
435 | |||
436 | rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | ||
437 | NFC_DIGITAL_FRAMING_NFCF); | ||
438 | if (rc) | ||
439 | return rc; | ||
440 | |||
441 | size = sizeof(struct digital_sensf_req); | ||
442 | |||
443 | skb = digital_skb_alloc(ddev, size); | ||
444 | if (!skb) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | skb_put(skb, size); | ||
448 | |||
449 | sensf_req = (struct digital_sensf_req *)skb->data; | ||
450 | sensf_req->cmd = DIGITAL_CMD_SENSF_REQ; | ||
451 | sensf_req->sc1 = 0xFF; | ||
452 | sensf_req->sc2 = 0xFF; | ||
453 | sensf_req->rc = 0; | ||
454 | sensf_req->tsn = 0; | ||
455 | |||
456 | *skb_push(skb, 1) = size + 1; | ||
457 | |||
458 | if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) | ||
459 | digital_skb_add_crc_f(skb); | ||
460 | |||
461 | rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sensf_res, | ||
462 | NULL); | ||
463 | if (rc) | ||
464 | kfree_skb(skb); | ||
465 | |||
466 | return rc; | ||
467 | } | ||