Commit 019c4fbaa790e2b3f11dab0c8b7d9896d77db3e5
Committed by
John W. Linville
1 parent
25a1d9dc85
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
NFC: Add NCI multiple targets support
Add the ability to select between multiple targets in NCI. If only one target is found, it will be auto-activated. If more than one target is found, then DISCOVER_NTF will be generated for each target, and the host should select one by calling DISCOVER_SELECT_CMD. Then, the target will be activated. If the activation fails, GENERIC_ERROR_NTF is generated. Signed-off-by: Ilan Elias <ilane@ti.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 5 changed files with 378 additions and 96 deletions Side-by-side Diff
include/net/nfc/nci.h
... | ... | @@ -116,6 +116,11 @@ |
116 | 116 | #define NCI_DISC_MAP_MODE_POLL 0x01 |
117 | 117 | #define NCI_DISC_MAP_MODE_LISTEN 0x02 |
118 | 118 | |
119 | +/* NCI Discover Notification Type */ | |
120 | +#define NCI_DISCOVER_NTF_TYPE_LAST 0x00 | |
121 | +#define NCI_DISCOVER_NTF_TYPE_LAST_NFCC 0x01 | |
122 | +#define NCI_DISCOVER_NTF_TYPE_MORE 0x02 | |
123 | + | |
119 | 124 | /* NCI Deactivation Type */ |
120 | 125 | #define NCI_DEACTIVATE_TYPE_IDLE_MODE 0x00 |
121 | 126 | #define NCI_DEACTIVATE_TYPE_SLEEP_MODE 0x01 |
... | ... | @@ -207,6 +212,13 @@ |
207 | 212 | struct disc_config disc_configs[NCI_MAX_NUM_RF_CONFIGS]; |
208 | 213 | } __packed; |
209 | 214 | |
215 | +#define NCI_OP_RF_DISCOVER_SELECT_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x04) | |
216 | +struct nci_rf_discover_select_cmd { | |
217 | + __u8 rf_discovery_id; | |
218 | + __u8 rf_protocol; | |
219 | + __u8 rf_interface; | |
220 | +} __packed; | |
221 | + | |
210 | 222 | #define NCI_OP_RF_DEACTIVATE_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x06) |
211 | 223 | struct nci_rf_deactivate_cmd { |
212 | 224 | __u8 type; |
... | ... | @@ -244,6 +256,8 @@ |
244 | 256 | |
245 | 257 | #define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03) |
246 | 258 | |
259 | +#define NCI_OP_RF_DISCOVER_SELECT_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x04) | |
260 | + | |
247 | 261 | #define NCI_OP_RF_DEACTIVATE_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x06) |
248 | 262 | |
249 | 263 | /* --------------------------- */ |
250 | 264 | |
... | ... | @@ -260,13 +274,15 @@ |
260 | 274 | struct conn_credit_entry conn_entries[NCI_MAX_NUM_CONN]; |
261 | 275 | } __packed; |
262 | 276 | |
277 | +#define NCI_OP_CORE_GENERIC_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x07) | |
278 | + | |
263 | 279 | #define NCI_OP_CORE_INTF_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x08) |
264 | 280 | struct nci_core_intf_error_ntf { |
265 | 281 | __u8 status; |
266 | 282 | __u8 conn_id; |
267 | 283 | } __packed; |
268 | 284 | |
269 | -#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05) | |
285 | +#define NCI_OP_RF_DISCOVER_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x03) | |
270 | 286 | struct rf_tech_specific_params_nfca_poll { |
271 | 287 | __u16 sens_res; |
272 | 288 | __u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */ |
... | ... | @@ -286,6 +302,22 @@ |
286 | 302 | __u8 sensf_res[18]; /* 16 or 18 Bytes */ |
287 | 303 | } __packed; |
288 | 304 | |
305 | +struct nci_rf_discover_ntf { | |
306 | + __u8 rf_discovery_id; | |
307 | + __u8 rf_protocol; | |
308 | + __u8 rf_tech_and_mode; | |
309 | + __u8 rf_tech_specific_params_len; | |
310 | + | |
311 | + union { | |
312 | + struct rf_tech_specific_params_nfca_poll nfca_poll; | |
313 | + struct rf_tech_specific_params_nfcb_poll nfcb_poll; | |
314 | + struct rf_tech_specific_params_nfcf_poll nfcf_poll; | |
315 | + } rf_tech_specific_params; | |
316 | + | |
317 | + __u8 ntf_type; | |
318 | +} __packed; | |
319 | + | |
320 | +#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05) | |
289 | 321 | struct activation_params_nfca_poll_iso_dep { |
290 | 322 | __u8 rats_res_len; |
291 | 323 | __u8 rats_res[20]; |
include/net/nfc/nci_core.h
... | ... | @@ -46,6 +46,8 @@ |
46 | 46 | enum nci_state { |
47 | 47 | NCI_IDLE, |
48 | 48 | NCI_DISCOVERY, |
49 | + NCI_W4_ALL_DISCOVERIES, | |
50 | + NCI_W4_HOST_SELECT, | |
49 | 51 | NCI_POLL_ACTIVE, |
50 | 52 | }; |
51 | 53 | |
... | ... | @@ -53,6 +55,7 @@ |
53 | 55 | #define NCI_RESET_TIMEOUT 5000 |
54 | 56 | #define NCI_INIT_TIMEOUT 5000 |
55 | 57 | #define NCI_RF_DISC_TIMEOUT 5000 |
58 | +#define NCI_RF_DISC_SELECT_TIMEOUT 5000 | |
56 | 59 | #define NCI_RF_DEACTIVATE_TIMEOUT 30000 |
57 | 60 | #define NCI_CMD_TIMEOUT 5000 |
58 | 61 | #define NCI_DATA_TIMEOUT 700 |
... | ... | @@ -66,6 +69,7 @@ |
66 | 69 | }; |
67 | 70 | |
68 | 71 | #define NCI_MAX_SUPPORTED_RF_INTERFACES 4 |
72 | +#define NCI_MAX_DISCOVERED_TARGETS 10 | |
69 | 73 | |
70 | 74 | /* NCI Core structures */ |
71 | 75 | struct nci_dev { |
72 | 76 | |
... | ... | @@ -105,9 +109,11 @@ |
105 | 109 | void *driver_data; |
106 | 110 | |
107 | 111 | __u32 poll_prots; |
108 | - __u32 target_available_prots; | |
109 | 112 | __u32 target_active_prot; |
110 | 113 | |
114 | + struct nfc_target targets[NCI_MAX_DISCOVERED_TARGETS]; | |
115 | + int n_targets; | |
116 | + | |
111 | 117 | /* received during NCI_OP_CORE_RESET_RSP */ |
112 | 118 | __u8 nci_ver; |
113 | 119 | |
... | ... | @@ -178,6 +184,7 @@ |
178 | 184 | int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb); |
179 | 185 | void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb, |
180 | 186 | int err); |
187 | +void nci_clear_target_list(struct nci_dev *ndev); | |
181 | 188 | |
182 | 189 | /* ----- NCI requests ----- */ |
183 | 190 | #define NCI_REQ_DONE 0 |
net/nfc/nci/core.c
... | ... | @@ -216,6 +216,39 @@ |
216 | 216 | &cmd); |
217 | 217 | } |
218 | 218 | |
219 | +struct nci_rf_discover_select_param { | |
220 | + __u8 rf_discovery_id; | |
221 | + __u8 rf_protocol; | |
222 | +}; | |
223 | + | |
224 | +static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt) | |
225 | +{ | |
226 | + struct nci_rf_discover_select_param *param = | |
227 | + (struct nci_rf_discover_select_param *)opt; | |
228 | + struct nci_rf_discover_select_cmd cmd; | |
229 | + | |
230 | + cmd.rf_discovery_id = param->rf_discovery_id; | |
231 | + cmd.rf_protocol = param->rf_protocol; | |
232 | + | |
233 | + switch (cmd.rf_protocol) { | |
234 | + case NCI_RF_PROTOCOL_ISO_DEP: | |
235 | + cmd.rf_interface = NCI_RF_INTERFACE_ISO_DEP; | |
236 | + break; | |
237 | + | |
238 | + case NCI_RF_PROTOCOL_NFC_DEP: | |
239 | + cmd.rf_interface = NCI_RF_INTERFACE_NFC_DEP; | |
240 | + break; | |
241 | + | |
242 | + default: | |
243 | + cmd.rf_interface = NCI_RF_INTERFACE_FRAME; | |
244 | + break; | |
245 | + } | |
246 | + | |
247 | + nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD, | |
248 | + sizeof(struct nci_rf_discover_select_cmd), | |
249 | + &cmd); | |
250 | +} | |
251 | + | |
219 | 252 | static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) |
220 | 253 | { |
221 | 254 | struct nci_rf_deactivate_cmd cmd; |
... | ... | @@ -264,6 +297,7 @@ |
264 | 297 | |
265 | 298 | if (!rc) { |
266 | 299 | set_bit(NCI_UP, &ndev->flags); |
300 | + nci_clear_target_list(ndev); | |
267 | 301 | atomic_set(&ndev->state, NCI_IDLE); |
268 | 302 | } else { |
269 | 303 | /* Init failed, cleanup */ |
... | ... | @@ -361,7 +395,8 @@ |
361 | 395 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
362 | 396 | int rc; |
363 | 397 | |
364 | - if (atomic_read(&ndev->state) == NCI_DISCOVERY) { | |
398 | + if ((atomic_read(&ndev->state) == NCI_DISCOVERY) || | |
399 | + (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) { | |
365 | 400 | pr_err("unable to start poll, since poll is already active\n"); |
366 | 401 | return -EBUSY; |
367 | 402 | } |
... | ... | @@ -371,8 +406,9 @@ |
371 | 406 | return -EBUSY; |
372 | 407 | } |
373 | 408 | |
374 | - if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { | |
375 | - pr_debug("target is active, implicitly deactivate...\n"); | |
409 | + if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) || | |
410 | + (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { | |
411 | + pr_debug("target active or w4 select, implicitly deactivate\n"); | |
376 | 412 | |
377 | 413 | rc = nci_request(ndev, nci_rf_deactivate_req, 0, |
378 | 414 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); |
... | ... | @@ -393,7 +429,8 @@ |
393 | 429 | { |
394 | 430 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
395 | 431 | |
396 | - if (atomic_read(&ndev->state) != NCI_DISCOVERY) { | |
432 | + if ((atomic_read(&ndev->state) != NCI_DISCOVERY) && | |
433 | + (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) { | |
397 | 434 | pr_err("unable to stop poll, since poll is not active\n"); |
398 | 435 | return; |
399 | 436 | } |
400 | 437 | |
... | ... | @@ -406,10 +443,15 @@ |
406 | 443 | __u32 protocol) |
407 | 444 | { |
408 | 445 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
446 | + struct nci_rf_discover_select_param param; | |
447 | + struct nfc_target *target = 0; | |
448 | + int i; | |
449 | + int rc = 0; | |
409 | 450 | |
410 | 451 | pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); |
411 | 452 | |
412 | - if (atomic_read(&ndev->state) != NCI_POLL_ACTIVE) { | |
453 | + if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) && | |
454 | + (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { | |
413 | 455 | pr_err("there is no available target to activate\n"); |
414 | 456 | return -EINVAL; |
415 | 457 | } |
416 | 458 | |
417 | 459 | |
... | ... | @@ -419,16 +461,47 @@ |
419 | 461 | return -EBUSY; |
420 | 462 | } |
421 | 463 | |
422 | - if (!(ndev->target_available_prots & (1 << protocol))) { | |
464 | + for (i = 0; i < ndev->n_targets; i++) { | |
465 | + if (ndev->targets[i].idx == target_idx) { | |
466 | + target = &ndev->targets[i]; | |
467 | + break; | |
468 | + } | |
469 | + } | |
470 | + | |
471 | + if (!target) { | |
472 | + pr_err("unable to find the selected target\n"); | |
473 | + return -EINVAL; | |
474 | + } | |
475 | + | |
476 | + if (!(target->supported_protocols & (1 << protocol))) { | |
423 | 477 | pr_err("target does not support the requested protocol 0x%x\n", |
424 | 478 | protocol); |
425 | 479 | return -EINVAL; |
426 | 480 | } |
427 | 481 | |
428 | - ndev->target_active_prot = protocol; | |
429 | - ndev->target_available_prots = 0; | |
482 | + if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { | |
483 | + param.rf_discovery_id = target->idx; | |
430 | 484 | |
431 | - return 0; | |
485 | + if (protocol == NFC_PROTO_JEWEL) | |
486 | + param.rf_protocol = NCI_RF_PROTOCOL_T1T; | |
487 | + else if (protocol == NFC_PROTO_MIFARE) | |
488 | + param.rf_protocol = NCI_RF_PROTOCOL_T2T; | |
489 | + else if (protocol == NFC_PROTO_FELICA) | |
490 | + param.rf_protocol = NCI_RF_PROTOCOL_T3T; | |
491 | + else if (protocol == NFC_PROTO_ISO14443) | |
492 | + param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; | |
493 | + else | |
494 | + param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; | |
495 | + | |
496 | + rc = nci_request(ndev, nci_rf_discover_select_req, | |
497 | + (unsigned long)¶m, | |
498 | + msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT)); | |
499 | + } | |
500 | + | |
501 | + if (!rc) | |
502 | + ndev->target_active_prot = protocol; | |
503 | + | |
504 | + return rc; | |
432 | 505 | } |
433 | 506 | |
434 | 507 | static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) |
net/nfc/nci/ntf.c
... | ... | @@ -71,6 +71,20 @@ |
71 | 71 | queue_work(ndev->tx_wq, &ndev->tx_work); |
72 | 72 | } |
73 | 73 | |
74 | +static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev, | |
75 | + struct sk_buff *skb) | |
76 | +{ | |
77 | + __u8 status = skb->data[0]; | |
78 | + | |
79 | + pr_debug("status 0x%x\n", status); | |
80 | + | |
81 | + if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { | |
82 | + /* Activation failed, so complete the request | |
83 | + (the state remains the same) */ | |
84 | + nci_req_complete(ndev, status); | |
85 | + } | |
86 | +} | |
87 | + | |
74 | 88 | static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, |
75 | 89 | struct sk_buff *skb) |
76 | 90 | { |
77 | 91 | |
... | ... | @@ -86,12 +100,9 @@ |
86 | 100 | } |
87 | 101 | |
88 | 102 | static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, |
89 | - struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | |
103 | + struct rf_tech_specific_params_nfca_poll *nfca_poll, | |
104 | + __u8 *data) | |
90 | 105 | { |
91 | - struct rf_tech_specific_params_nfca_poll *nfca_poll; | |
92 | - | |
93 | - nfca_poll = &ntf->rf_tech_specific_params.nfca_poll; | |
94 | - | |
95 | 106 | nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); |
96 | 107 | data += 2; |
97 | 108 | |
98 | 109 | |
... | ... | @@ -116,12 +127,9 @@ |
116 | 127 | } |
117 | 128 | |
118 | 129 | static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, |
119 | - struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | |
130 | + struct rf_tech_specific_params_nfcb_poll *nfcb_poll, | |
131 | + __u8 *data) | |
120 | 132 | { |
121 | - struct rf_tech_specific_params_nfcb_poll *nfcb_poll; | |
122 | - | |
123 | - nfcb_poll = &ntf->rf_tech_specific_params.nfcb_poll; | |
124 | - | |
125 | 133 | nfcb_poll->sensb_res_len = *data++; |
126 | 134 | |
127 | 135 | pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); |
128 | 136 | |
... | ... | @@ -133,12 +141,9 @@ |
133 | 141 | } |
134 | 142 | |
135 | 143 | static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, |
136 | - struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | |
144 | + struct rf_tech_specific_params_nfcf_poll *nfcf_poll, | |
145 | + __u8 *data) | |
137 | 146 | { |
138 | - struct rf_tech_specific_params_nfcf_poll *nfcf_poll; | |
139 | - | |
140 | - nfcf_poll = &ntf->rf_tech_specific_params.nfcf_poll; | |
141 | - | |
142 | 147 | nfcf_poll->bit_rate = *data++; |
143 | 148 | nfcf_poll->sensf_res_len = *data++; |
144 | 149 | |
... | ... | @@ -151,6 +156,172 @@ |
151 | 156 | return data; |
152 | 157 | } |
153 | 158 | |
159 | +static int nci_add_new_protocol(struct nci_dev *ndev, | |
160 | + struct nfc_target *target, | |
161 | + __u8 rf_protocol, | |
162 | + __u8 rf_tech_and_mode, | |
163 | + void *params) | |
164 | +{ | |
165 | + struct rf_tech_specific_params_nfca_poll *nfca_poll; | |
166 | + struct rf_tech_specific_params_nfcb_poll *nfcb_poll; | |
167 | + struct rf_tech_specific_params_nfcf_poll *nfcf_poll; | |
168 | + __u32 protocol; | |
169 | + | |
170 | + if (rf_protocol == NCI_RF_PROTOCOL_T2T) | |
171 | + protocol = NFC_PROTO_MIFARE_MASK; | |
172 | + else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) | |
173 | + protocol = NFC_PROTO_ISO14443_MASK; | |
174 | + else if (rf_protocol == NCI_RF_PROTOCOL_T3T) | |
175 | + protocol = NFC_PROTO_FELICA_MASK; | |
176 | + else | |
177 | + protocol = 0; | |
178 | + | |
179 | + if (!(protocol & ndev->poll_prots)) { | |
180 | + pr_err("the target found does not have the desired protocol\n"); | |
181 | + return -EPROTO; | |
182 | + } | |
183 | + | |
184 | + if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { | |
185 | + nfca_poll = (struct rf_tech_specific_params_nfca_poll *)params; | |
186 | + | |
187 | + target->sens_res = nfca_poll->sens_res; | |
188 | + target->sel_res = nfca_poll->sel_res; | |
189 | + target->nfcid1_len = nfca_poll->nfcid1_len; | |
190 | + if (target->nfcid1_len > 0) { | |
191 | + memcpy(target->nfcid1, nfca_poll->nfcid1, | |
192 | + target->nfcid1_len); | |
193 | + } | |
194 | + } else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) { | |
195 | + nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params; | |
196 | + | |
197 | + target->sensb_res_len = nfcb_poll->sensb_res_len; | |
198 | + if (target->sensb_res_len > 0) { | |
199 | + memcpy(target->sensb_res, nfcb_poll->sensb_res, | |
200 | + target->sensb_res_len); | |
201 | + } | |
202 | + } else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) { | |
203 | + nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params; | |
204 | + | |
205 | + target->sensf_res_len = nfcf_poll->sensf_res_len; | |
206 | + if (target->sensf_res_len > 0) { | |
207 | + memcpy(target->sensf_res, nfcf_poll->sensf_res, | |
208 | + target->sensf_res_len); | |
209 | + } | |
210 | + } else { | |
211 | + pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode); | |
212 | + return -EPROTO; | |
213 | + } | |
214 | + | |
215 | + target->supported_protocols |= protocol; | |
216 | + | |
217 | + pr_debug("protocol 0x%x\n", protocol); | |
218 | + | |
219 | + return 0; | |
220 | +} | |
221 | + | |
222 | +static void nci_add_new_target(struct nci_dev *ndev, | |
223 | + struct nci_rf_discover_ntf *ntf) | |
224 | +{ | |
225 | + struct nfc_target *target; | |
226 | + int i, rc; | |
227 | + | |
228 | + for (i = 0; i < ndev->n_targets; i++) { | |
229 | + target = &ndev->targets[i]; | |
230 | + if (target->idx == ntf->rf_discovery_id) { | |
231 | + /* This target already exists, add the new protocol */ | |
232 | + nci_add_new_protocol(ndev, target, ntf->rf_protocol, | |
233 | + ntf->rf_tech_and_mode, | |
234 | + &ntf->rf_tech_specific_params); | |
235 | + return; | |
236 | + } | |
237 | + } | |
238 | + | |
239 | + /* This is a new target, check if we've enough room */ | |
240 | + if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) { | |
241 | + pr_debug("not enough room, ignoring new target...\n"); | |
242 | + return; | |
243 | + } | |
244 | + | |
245 | + target = &ndev->targets[ndev->n_targets]; | |
246 | + | |
247 | + rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, | |
248 | + ntf->rf_tech_and_mode, | |
249 | + &ntf->rf_tech_specific_params); | |
250 | + if (!rc) { | |
251 | + target->idx = ntf->rf_discovery_id; | |
252 | + ndev->n_targets++; | |
253 | + | |
254 | + pr_debug("target_idx %d, n_targets %d\n", target->idx, | |
255 | + ndev->n_targets); | |
256 | + } | |
257 | +} | |
258 | + | |
259 | +void nci_clear_target_list(struct nci_dev *ndev) | |
260 | +{ | |
261 | + memset(ndev->targets, 0, | |
262 | + (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS)); | |
263 | + | |
264 | + ndev->n_targets = 0; | |
265 | +} | |
266 | + | |
267 | +static void nci_rf_discover_ntf_packet(struct nci_dev *ndev, | |
268 | + struct sk_buff *skb) | |
269 | +{ | |
270 | + struct nci_rf_discover_ntf ntf; | |
271 | + __u8 *data = skb->data; | |
272 | + bool add_target = true; | |
273 | + | |
274 | + ntf.rf_discovery_id = *data++; | |
275 | + ntf.rf_protocol = *data++; | |
276 | + ntf.rf_tech_and_mode = *data++; | |
277 | + ntf.rf_tech_specific_params_len = *data++; | |
278 | + | |
279 | + pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id); | |
280 | + pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol); | |
281 | + pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode); | |
282 | + pr_debug("rf_tech_specific_params_len %d\n", | |
283 | + ntf.rf_tech_specific_params_len); | |
284 | + | |
285 | + if (ntf.rf_tech_specific_params_len > 0) { | |
286 | + switch (ntf.rf_tech_and_mode) { | |
287 | + case NCI_NFC_A_PASSIVE_POLL_MODE: | |
288 | + data = nci_extract_rf_params_nfca_passive_poll(ndev, | |
289 | + &(ntf.rf_tech_specific_params.nfca_poll), data); | |
290 | + break; | |
291 | + | |
292 | + case NCI_NFC_B_PASSIVE_POLL_MODE: | |
293 | + data = nci_extract_rf_params_nfcb_passive_poll(ndev, | |
294 | + &(ntf.rf_tech_specific_params.nfcb_poll), data); | |
295 | + break; | |
296 | + | |
297 | + case NCI_NFC_F_PASSIVE_POLL_MODE: | |
298 | + data = nci_extract_rf_params_nfcf_passive_poll(ndev, | |
299 | + &(ntf.rf_tech_specific_params.nfcf_poll), data); | |
300 | + break; | |
301 | + | |
302 | + default: | |
303 | + pr_err("unsupported rf_tech_and_mode 0x%x\n", | |
304 | + ntf.rf_tech_and_mode); | |
305 | + data += ntf.rf_tech_specific_params_len; | |
306 | + add_target = false; | |
307 | + } | |
308 | + } | |
309 | + | |
310 | + ntf.ntf_type = *data++; | |
311 | + pr_debug("ntf_type %d\n", ntf.ntf_type); | |
312 | + | |
313 | + if (add_target == true) | |
314 | + nci_add_new_target(ndev, &ntf); | |
315 | + | |
316 | + if (ntf.ntf_type == NCI_DISCOVER_NTF_TYPE_MORE) { | |
317 | + atomic_set(&ndev->state, NCI_W4_ALL_DISCOVERIES); | |
318 | + } else { | |
319 | + atomic_set(&ndev->state, NCI_W4_HOST_SELECT); | |
320 | + nfc_targets_found(ndev->nfc_dev, ndev->targets, | |
321 | + ndev->n_targets); | |
322 | + } | |
323 | +} | |
324 | + | |
154 | 325 | static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, |
155 | 326 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) |
156 | 327 | { |
157 | 328 | |
158 | 329 | |
159 | 330 | |
160 | 331 | |
161 | 332 | |
162 | 333 | |
163 | 334 | |
164 | 335 | |
165 | 336 | |
... | ... | @@ -184,74 +355,32 @@ |
184 | 355 | default: |
185 | 356 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", |
186 | 357 | ntf->activation_rf_tech_and_mode); |
187 | - return -EPROTO; | |
358 | + return NCI_STATUS_RF_PROTOCOL_ERROR; | |
188 | 359 | } |
189 | 360 | |
190 | - return 0; | |
361 | + return NCI_STATUS_OK; | |
191 | 362 | } |
192 | 363 | |
193 | -static void nci_target_found(struct nci_dev *ndev, | |
194 | - struct nci_rf_intf_activated_ntf *ntf) | |
364 | +static void nci_target_auto_activated(struct nci_dev *ndev, | |
365 | + struct nci_rf_intf_activated_ntf *ntf) | |
195 | 366 | { |
196 | - struct nfc_target nfc_tgt; | |
367 | + struct nfc_target *target; | |
368 | + int rc; | |
197 | 369 | |
198 | - memset(&nfc_tgt, 0, sizeof(nfc_tgt)); | |
370 | + target = &ndev->targets[ndev->n_targets]; | |
199 | 371 | |
200 | - if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T) | |
201 | - nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK; | |
202 | - else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) | |
203 | - nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK; | |
204 | - else if (ntf->rf_protocol == NCI_RF_PROTOCOL_T3T) | |
205 | - nfc_tgt.supported_protocols = NFC_PROTO_FELICA_MASK; | |
206 | - | |
207 | - if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) { | |
208 | - pr_debug("the target found does not have the desired protocol\n"); | |
372 | + rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, | |
373 | + ntf->activation_rf_tech_and_mode, | |
374 | + &ntf->rf_tech_specific_params); | |
375 | + if (rc) | |
209 | 376 | return; |
210 | - } | |
211 | 377 | |
212 | - pr_debug("new target found, supported_protocols 0x%x\n", | |
213 | - nfc_tgt.supported_protocols); | |
378 | + target->idx = ntf->rf_discovery_id; | |
379 | + ndev->n_targets++; | |
214 | 380 | |
215 | - if (ntf->activation_rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { | |
216 | - nfc_tgt.sens_res = | |
217 | - ntf->rf_tech_specific_params.nfca_poll.sens_res; | |
218 | - nfc_tgt.sel_res = | |
219 | - ntf->rf_tech_specific_params.nfca_poll.sel_res; | |
220 | - nfc_tgt.nfcid1_len = | |
221 | - ntf->rf_tech_specific_params.nfca_poll.nfcid1_len; | |
222 | - if (nfc_tgt.nfcid1_len > 0) { | |
223 | - memcpy(nfc_tgt.nfcid1, | |
224 | - ntf->rf_tech_specific_params.nfca_poll.nfcid1, | |
225 | - nfc_tgt.nfcid1_len); | |
226 | - } | |
227 | - } else if (ntf->activation_rf_tech_and_mode == | |
228 | - NCI_NFC_B_PASSIVE_POLL_MODE) { | |
229 | - nfc_tgt.sensb_res_len = | |
230 | - ntf->rf_tech_specific_params.nfcb_poll.sensb_res_len; | |
231 | - if (nfc_tgt.sensb_res_len > 0) { | |
232 | - memcpy(nfc_tgt.sensb_res, | |
233 | - ntf->rf_tech_specific_params.nfcb_poll.sensb_res, | |
234 | - nfc_tgt.sensb_res_len); | |
235 | - } | |
236 | - } else if (ntf->activation_rf_tech_and_mode == | |
237 | - NCI_NFC_F_PASSIVE_POLL_MODE) { | |
238 | - nfc_tgt.sensf_res_len = | |
239 | - ntf->rf_tech_specific_params.nfcf_poll.sensf_res_len; | |
240 | - if (nfc_tgt.sensf_res_len > 0) { | |
241 | - memcpy(nfc_tgt.sensf_res, | |
242 | - ntf->rf_tech_specific_params.nfcf_poll.sensf_res, | |
243 | - nfc_tgt.sensf_res_len); | |
244 | - } | |
245 | - } | |
381 | + pr_debug("target_idx %d, n_targets %d\n", target->idx, ndev->n_targets); | |
246 | 382 | |
247 | - ndev->target_available_prots = nfc_tgt.supported_protocols; | |
248 | - ndev->max_data_pkt_payload_size = ntf->max_data_pkt_payload_size; | |
249 | - ndev->initial_num_credits = ntf->initial_num_credits; | |
250 | - | |
251 | - /* set the available credits to initial value */ | |
252 | - atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); | |
253 | - | |
254 | - nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1); | |
383 | + nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets); | |
255 | 384 | } |
256 | 385 | |
257 | 386 | static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, |
258 | 387 | |
... | ... | @@ -259,10 +388,8 @@ |
259 | 388 | { |
260 | 389 | struct nci_rf_intf_activated_ntf ntf; |
261 | 390 | __u8 *data = skb->data; |
262 | - int err = 0; | |
391 | + int err = NCI_STATUS_OK; | |
263 | 392 | |
264 | - atomic_set(&ndev->state, NCI_POLL_ACTIVE); | |
265 | - | |
266 | 393 | ntf.rf_discovery_id = *data++; |
267 | 394 | ntf.rf_interface = *data++; |
268 | 395 | ntf.rf_protocol = *data++; |
269 | 396 | |
270 | 397 | |
271 | 398 | |
... | ... | @@ -286,23 +413,24 @@ |
286 | 413 | switch (ntf.activation_rf_tech_and_mode) { |
287 | 414 | case NCI_NFC_A_PASSIVE_POLL_MODE: |
288 | 415 | data = nci_extract_rf_params_nfca_passive_poll(ndev, |
289 | - &ntf, data); | |
416 | + &(ntf.rf_tech_specific_params.nfca_poll), data); | |
290 | 417 | break; |
291 | 418 | |
292 | 419 | case NCI_NFC_B_PASSIVE_POLL_MODE: |
293 | 420 | data = nci_extract_rf_params_nfcb_passive_poll(ndev, |
294 | - &ntf, data); | |
421 | + &(ntf.rf_tech_specific_params.nfcb_poll), data); | |
295 | 422 | break; |
296 | 423 | |
297 | 424 | case NCI_NFC_F_PASSIVE_POLL_MODE: |
298 | 425 | data = nci_extract_rf_params_nfcf_passive_poll(ndev, |
299 | - &ntf, data); | |
426 | + &(ntf.rf_tech_specific_params.nfcf_poll), data); | |
300 | 427 | break; |
301 | 428 | |
302 | 429 | default: |
303 | 430 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", |
304 | 431 | ntf.activation_rf_tech_and_mode); |
305 | - return; | |
432 | + err = NCI_STATUS_RF_PROTOCOL_ERROR; | |
433 | + goto exit; | |
306 | 434 | } |
307 | 435 | } |
308 | 436 | |
309 | 437 | |
... | ... | @@ -334,12 +462,30 @@ |
334 | 462 | default: |
335 | 463 | pr_err("unsupported rf_interface 0x%x\n", |
336 | 464 | ntf.rf_interface); |
337 | - return; | |
465 | + err = NCI_STATUS_RF_PROTOCOL_ERROR; | |
466 | + break; | |
338 | 467 | } |
339 | 468 | } |
340 | 469 | |
341 | - if (!err) | |
342 | - nci_target_found(ndev, &ntf); | |
470 | +exit: | |
471 | + if (err == NCI_STATUS_OK) { | |
472 | + ndev->max_data_pkt_payload_size = ntf.max_data_pkt_payload_size; | |
473 | + ndev->initial_num_credits = ntf.initial_num_credits; | |
474 | + | |
475 | + /* set the available credits to initial value */ | |
476 | + atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); | |
477 | + } | |
478 | + | |
479 | + if (atomic_read(&ndev->state) == NCI_DISCOVERY) { | |
480 | + /* A single target was found and activated automatically */ | |
481 | + atomic_set(&ndev->state, NCI_POLL_ACTIVE); | |
482 | + if (err == NCI_STATUS_OK) | |
483 | + nci_target_auto_activated(ndev, &ntf); | |
484 | + } else { /* ndev->state == NCI_W4_HOST_SELECT */ | |
485 | + /* A selected target was activated, so complete the request */ | |
486 | + atomic_set(&ndev->state, NCI_POLL_ACTIVE); | |
487 | + nci_req_complete(ndev, err); | |
488 | + } | |
343 | 489 | } |
344 | 490 | |
345 | 491 | static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, |
... | ... | @@ -349,9 +495,6 @@ |
349 | 495 | |
350 | 496 | pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason); |
351 | 497 | |
352 | - atomic_set(&ndev->state, NCI_IDLE); | |
353 | - ndev->target_active_prot = 0; | |
354 | - | |
355 | 498 | /* drop tx data queue */ |
356 | 499 | skb_queue_purge(&ndev->tx_q); |
357 | 500 | |
... | ... | @@ -365,6 +508,8 @@ |
365 | 508 | if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) |
366 | 509 | nci_data_exchange_complete(ndev, NULL, -EIO); |
367 | 510 | |
511 | + nci_clear_target_list(ndev); | |
512 | + atomic_set(&ndev->state, NCI_IDLE); | |
368 | 513 | nci_req_complete(ndev, NCI_STATUS_OK); |
369 | 514 | } |
370 | 515 | |
371 | 516 | |
... | ... | @@ -386,8 +531,16 @@ |
386 | 531 | nci_core_conn_credits_ntf_packet(ndev, skb); |
387 | 532 | break; |
388 | 533 | |
534 | + case NCI_OP_CORE_GENERIC_ERROR_NTF: | |
535 | + nci_core_generic_error_ntf_packet(ndev, skb); | |
536 | + break; | |
537 | + | |
389 | 538 | case NCI_OP_CORE_INTF_ERROR_NTF: |
390 | 539 | nci_core_conn_intf_error_ntf_packet(ndev, skb); |
540 | + break; | |
541 | + | |
542 | + case NCI_OP_RF_DISCOVER_NTF: | |
543 | + nci_rf_discover_ntf_packet(ndev, skb); | |
391 | 544 | break; |
392 | 545 | |
393 | 546 | case NCI_OP_RF_INTF_ACTIVATED_NTF: |
net/nfc/nci/rsp.c
... | ... | @@ -142,6 +142,18 @@ |
142 | 142 | nci_req_complete(ndev, status); |
143 | 143 | } |
144 | 144 | |
145 | +static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev, | |
146 | + struct sk_buff *skb) | |
147 | +{ | |
148 | + __u8 status = skb->data[0]; | |
149 | + | |
150 | + pr_debug("status 0x%x\n", status); | |
151 | + | |
152 | + /* Complete the request on intf_activated_ntf or generic_error_ntf */ | |
153 | + if (status != NCI_STATUS_OK) | |
154 | + nci_req_complete(ndev, status); | |
155 | +} | |
156 | + | |
145 | 157 | static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, |
146 | 158 | struct sk_buff *skb) |
147 | 159 | { |
... | ... | @@ -152,6 +164,7 @@ |
152 | 164 | /* If target was active, complete the request only in deactivate_ntf */ |
153 | 165 | if ((status != NCI_STATUS_OK) || |
154 | 166 | (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { |
167 | + nci_clear_target_list(ndev); | |
155 | 168 | atomic_set(&ndev->state, NCI_IDLE); |
156 | 169 | nci_req_complete(ndev, status); |
157 | 170 | } |
... | ... | @@ -188,6 +201,10 @@ |
188 | 201 | |
189 | 202 | case NCI_OP_RF_DISCOVER_RSP: |
190 | 203 | nci_rf_disc_rsp_packet(ndev, skb); |
204 | + break; | |
205 | + | |
206 | + case NCI_OP_RF_DISCOVER_SELECT_RSP: | |
207 | + nci_rf_disc_select_rsp_packet(ndev, skb); | |
191 | 208 | break; |
192 | 209 | |
193 | 210 | case NCI_OP_RF_DEACTIVATE_RSP: |