diff options
Diffstat (limited to 'net/nfc/digital_technology.c')
-rw-r--r-- | net/nfc/digital_technology.c | 247 |
1 files changed, 245 insertions, 2 deletions
diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index 251c8c753ebe..278c3fed27e0 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) |
@@ -51,6 +52,34 @@ | |||
51 | #define DIGITAL_SENSF_REQ_RC_SC 1 | 52 | #define DIGITAL_SENSF_REQ_RC_SC 1 |
52 | #define DIGITAL_SENSF_REQ_RC_AP 2 | 53 | #define DIGITAL_SENSF_REQ_RC_AP 2 |
53 | 54 | ||
55 | #define DIGITAL_CMD_ISO15693_INVENTORY_REQ 0x01 | ||
56 | |||
57 | #define DIGITAL_ISO15693_REQ_FLAG_DATA_RATE BIT(1) | ||
58 | #define DIGITAL_ISO15693_REQ_FLAG_INVENTORY BIT(2) | ||
59 | #define DIGITAL_ISO15693_REQ_FLAG_NB_SLOTS BIT(5) | ||
60 | #define DIGITAL_ISO15693_RES_FLAG_ERROR BIT(0) | ||
61 | #define DIGITAL_ISO15693_RES_IS_VALID(flags) \ | ||
62 | (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) | ||
63 | |||
64 | #define DIGITAL_ISO_DEP_I_PCB 0x02 | ||
65 | #define DIGITAL_ISO_DEP_PNI(pni) ((pni) & 0x01) | ||
66 | |||
67 | #define DIGITAL_ISO_DEP_PCB_TYPE(pcb) ((pcb) & 0xC0) | ||
68 | |||
69 | #define DIGITAL_ISO_DEP_I_BLOCK 0x00 | ||
70 | |||
71 | #define DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb) ((pcb) & 0x08) | ||
72 | |||
73 | static const u8 digital_ats_fsc[] = { | ||
74 | 16, 24, 32, 40, 48, 64, 96, 128, | ||
75 | }; | ||
76 | |||
77 | #define DIGITAL_ATS_FSCI(t0) ((t0) & 0x0F) | ||
78 | #define DIGITAL_ATS_MAX_FSC 256 | ||
79 | |||
80 | #define DIGITAL_RATS_BYTE1 0xE0 | ||
81 | #define DIGITAL_RATS_PARAM 0x80 | ||
82 | |||
54 | struct digital_sdd_res { | 83 | struct digital_sdd_res { |
55 | u8 nfcid1[4]; | 84 | u8 nfcid1[4]; |
56 | u8 bcc; | 85 | u8 bcc; |
@@ -82,9 +111,127 @@ struct digital_sensf_res { | |||
82 | u8 rd[2]; | 111 | u8 rd[2]; |
83 | } __packed; | 112 | } __packed; |
84 | 113 | ||
114 | struct digital_iso15693_inv_req { | ||
115 | u8 flags; | ||
116 | u8 cmd; | ||
117 | u8 mask_len; | ||
118 | u64 mask; | ||
119 | } __packed; | ||
120 | |||
121 | struct digital_iso15693_inv_res { | ||
122 | u8 flags; | ||
123 | u8 dsfid; | ||
124 | u64 uid; | ||
125 | } __packed; | ||
126 | |||
85 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, | 127 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, |
86 | struct nfc_target *target); | 128 | struct nfc_target *target); |
87 | 129 | ||
130 | int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, | ||
131 | struct sk_buff *skb) | ||
132 | { | ||
133 | u8 pcb; | ||
134 | u8 block_type; | ||
135 | |||
136 | if (skb->len < 1) | ||
137 | return -EIO; | ||
138 | |||
139 | pcb = *skb->data; | ||
140 | block_type = DIGITAL_ISO_DEP_PCB_TYPE(pcb); | ||
141 | |||
142 | /* No support fo R-block nor S-block */ | ||
143 | if (block_type != DIGITAL_ISO_DEP_I_BLOCK) { | ||
144 | pr_err("ISO_DEP R-block and S-block not supported\n"); | ||
145 | return -EIO; | ||
146 | } | ||
147 | |||
148 | if (DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb)) { | ||
149 | pr_err("DID field in ISO_DEP PCB not supported\n"); | ||
150 | return -EIO; | ||
151 | } | ||
152 | |||
153 | skb_pull(skb, 1); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, | ||
159 | struct sk_buff *skb) | ||
160 | { | ||
161 | /* | ||
162 | * Chaining not supported so skb->len + 1 PCB byte + 2 CRC bytes must | ||
163 | * not be greater than remote FSC | ||
164 | */ | ||
165 | if (skb->len + 3 > ddev->target_fsc) | ||
166 | return -EIO; | ||
167 | |||
168 | skb_push(skb, 1); | ||
169 | |||
170 | *skb->data = DIGITAL_ISO_DEP_I_PCB | ddev->curr_nfc_dep_pni; | ||
171 | |||
172 | ddev->curr_nfc_dep_pni = | ||
173 | DIGITAL_ISO_DEP_PNI(ddev->curr_nfc_dep_pni + 1); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, | ||
179 | struct sk_buff *resp) | ||
180 | { | ||
181 | struct nfc_target *target = arg; | ||
182 | u8 fsdi; | ||
183 | int rc; | ||
184 | |||
185 | if (IS_ERR(resp)) { | ||
186 | rc = PTR_ERR(resp); | ||
187 | resp = NULL; | ||
188 | goto exit; | ||
189 | } | ||
190 | |||
191 | if (resp->len < 2) { | ||
192 | rc = -EIO; | ||
193 | goto exit; | ||
194 | } | ||
195 | |||
196 | fsdi = DIGITAL_ATS_FSCI(resp->data[1]); | ||
197 | if (fsdi >= 8) | ||
198 | ddev->target_fsc = DIGITAL_ATS_MAX_FSC; | ||
199 | else | ||
200 | ddev->target_fsc = digital_ats_fsc[fsdi]; | ||
201 | |||
202 | ddev->curr_nfc_dep_pni = 0; | ||
203 | |||
204 | rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443); | ||
205 | |||
206 | exit: | ||
207 | dev_kfree_skb(resp); | ||
208 | kfree(target); | ||
209 | |||
210 | if (rc) | ||
211 | digital_poll_next_tech(ddev); | ||
212 | } | ||
213 | |||
214 | static int digital_in_send_rats(struct nfc_digital_dev *ddev, | ||
215 | struct nfc_target *target) | ||
216 | { | ||
217 | int rc; | ||
218 | struct sk_buff *skb; | ||
219 | |||
220 | skb = digital_skb_alloc(ddev, 2); | ||
221 | if (!skb) | ||
222 | return -ENOMEM; | ||
223 | |||
224 | *skb_put(skb, 1) = DIGITAL_RATS_BYTE1; | ||
225 | *skb_put(skb, 1) = DIGITAL_RATS_PARAM; | ||
226 | |||
227 | rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_ats, | ||
228 | target); | ||
229 | if (rc) | ||
230 | kfree_skb(skb); | ||
231 | |||
232 | return rc; | ||
233 | } | ||
234 | |||
88 | static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | 235 | static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, |
89 | struct sk_buff *resp) | 236 | struct sk_buff *resp) |
90 | { | 237 | { |
@@ -122,8 +269,19 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | |||
122 | goto exit_free_skb; | 269 | goto exit_free_skb; |
123 | } | 270 | } |
124 | 271 | ||
272 | target->sel_res = sel_res; | ||
273 | |||
125 | if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { | 274 | if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { |
126 | nfc_proto = NFC_PROTO_MIFARE; | 275 | nfc_proto = NFC_PROTO_MIFARE; |
276 | } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { | ||
277 | rc = digital_in_send_rats(ddev, target); | ||
278 | if (rc) | ||
279 | goto exit; | ||
280 | /* | ||
281 | * Skip target_found and don't free it for now. This will be | ||
282 | * done when receiving the ATS | ||
283 | */ | ||
284 | goto exit_free_skb; | ||
127 | } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { | 285 | } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { |
128 | nfc_proto = NFC_PROTO_NFC_DEP; | 286 | nfc_proto = NFC_PROTO_NFC_DEP; |
129 | } else { | 287 | } else { |
@@ -131,8 +289,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | |||
131 | goto exit; | 289 | goto exit; |
132 | } | 290 | } |
133 | 291 | ||
134 | target->sel_res = sel_res; | ||
135 | |||
136 | rc = digital_target_found(ddev, target, nfc_proto); | 292 | rc = digital_target_found(ddev, target, nfc_proto); |
137 | 293 | ||
138 | exit: | 294 | exit: |
@@ -473,6 +629,93 @@ int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech) | |||
473 | return rc; | 629 | return rc; |
474 | } | 630 | } |
475 | 631 | ||
632 | static void digital_in_recv_iso15693_inv_res(struct nfc_digital_dev *ddev, | ||
633 | void *arg, struct sk_buff *resp) | ||
634 | { | ||
635 | struct digital_iso15693_inv_res *res; | ||
636 | struct nfc_target *target = NULL; | ||
637 | int rc; | ||
638 | |||
639 | if (IS_ERR(resp)) { | ||
640 | rc = PTR_ERR(resp); | ||
641 | resp = NULL; | ||
642 | goto out_free_skb; | ||
643 | } | ||
644 | |||
645 | if (resp->len != sizeof(*res)) { | ||
646 | rc = -EIO; | ||
647 | goto out_free_skb; | ||
648 | } | ||
649 | |||
650 | res = (struct digital_iso15693_inv_res *)resp->data; | ||
651 | |||
652 | if (!DIGITAL_ISO15693_RES_IS_VALID(res->flags)) { | ||
653 | PROTOCOL_ERR("ISO15693 - 10.3.1"); | ||
654 | rc = -EINVAL; | ||
655 | goto out_free_skb; | ||
656 | } | ||
657 | |||
658 | target = kzalloc(sizeof(*target), GFP_KERNEL); | ||
659 | if (!target) { | ||
660 | rc = -ENOMEM; | ||
661 | goto out_free_skb; | ||
662 | } | ||
663 | |||
664 | target->is_iso15693 = 1; | ||
665 | target->iso15693_dsfid = res->dsfid; | ||
666 | memcpy(target->iso15693_uid, &res->uid, sizeof(target->iso15693_uid)); | ||
667 | |||
668 | rc = digital_target_found(ddev, target, NFC_PROTO_ISO15693); | ||
669 | |||
670 | kfree(target); | ||
671 | |||
672 | out_free_skb: | ||
673 | dev_kfree_skb(resp); | ||
674 | |||
675 | if (rc) | ||
676 | digital_poll_next_tech(ddev); | ||
677 | } | ||
678 | |||
679 | int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech) | ||
680 | { | ||
681 | struct digital_iso15693_inv_req *req; | ||
682 | struct sk_buff *skb; | ||
683 | int rc; | ||
684 | |||
685 | rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, | ||
686 | NFC_DIGITAL_RF_TECH_ISO15693); | ||
687 | if (rc) | ||
688 | return rc; | ||
689 | |||
690 | rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | ||
691 | NFC_DIGITAL_FRAMING_ISO15693_INVENTORY); | ||
692 | if (rc) | ||
693 | return rc; | ||
694 | |||
695 | skb = digital_skb_alloc(ddev, sizeof(*req)); | ||
696 | if (!skb) | ||
697 | return -ENOMEM; | ||
698 | |||
699 | skb_put(skb, sizeof(*req) - sizeof(req->mask)); /* No mask */ | ||
700 | req = (struct digital_iso15693_inv_req *)skb->data; | ||
701 | |||
702 | /* Single sub-carrier, high data rate, no AFI, single slot | ||
703 | * Inventory command | ||
704 | */ | ||
705 | req->flags = DIGITAL_ISO15693_REQ_FLAG_DATA_RATE | | ||
706 | DIGITAL_ISO15693_REQ_FLAG_INVENTORY | | ||
707 | DIGITAL_ISO15693_REQ_FLAG_NB_SLOTS; | ||
708 | req->cmd = DIGITAL_CMD_ISO15693_INVENTORY_REQ; | ||
709 | req->mask_len = 0; | ||
710 | |||
711 | rc = digital_in_send_cmd(ddev, skb, 30, | ||
712 | digital_in_recv_iso15693_inv_res, NULL); | ||
713 | if (rc) | ||
714 | kfree_skb(skb); | ||
715 | |||
716 | return rc; | ||
717 | } | ||
718 | |||
476 | static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) | 719 | static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) |
477 | { | 720 | { |
478 | struct sk_buff *skb; | 721 | struct sk_buff *skb; |