diff options
author | Ilan Elias <ilane@ti.com> | 2012-01-18 06:16:14 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-01-24 14:32:29 -0500 |
commit | 019c4fbaa790e2b3f11dab0c8b7d9896d77db3e5 (patch) | |
tree | 593fc051bc96a40e48406f6cba883b1f95822422 /net/nfc | |
parent | 25a1d9dc850b1bdcc4760eb625f0a67057f54d26 (diff) |
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>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/nci/core.c | 91 | ||||
-rw-r--r-- | net/nfc/nci/ntf.c | 323 | ||||
-rw-r--r-- | net/nfc/nci/rsp.c | 17 |
3 files changed, 337 insertions, 94 deletions
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 629b76845973..12d1d4d62672 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -216,6 +216,39 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | |||
216 | &cmd); | 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 | static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) | 252 | static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) |
220 | { | 253 | { |
221 | struct nci_rf_deactivate_cmd cmd; | 254 | struct nci_rf_deactivate_cmd cmd; |
@@ -264,6 +297,7 @@ static int nci_open_device(struct nci_dev *ndev) | |||
264 | 297 | ||
265 | if (!rc) { | 298 | if (!rc) { |
266 | set_bit(NCI_UP, &ndev->flags); | 299 | set_bit(NCI_UP, &ndev->flags); |
300 | nci_clear_target_list(ndev); | ||
267 | atomic_set(&ndev->state, NCI_IDLE); | 301 | atomic_set(&ndev->state, NCI_IDLE); |
268 | } else { | 302 | } else { |
269 | /* Init failed, cleanup */ | 303 | /* Init failed, cleanup */ |
@@ -361,7 +395,8 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) | |||
361 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 395 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
362 | int rc; | 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 | pr_err("unable to start poll, since poll is already active\n"); | 400 | pr_err("unable to start poll, since poll is already active\n"); |
366 | return -EBUSY; | 401 | return -EBUSY; |
367 | } | 402 | } |
@@ -371,8 +406,9 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) | |||
371 | return -EBUSY; | 406 | return -EBUSY; |
372 | } | 407 | } |
373 | 408 | ||
374 | if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { | 409 | if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) || |
375 | pr_debug("target is active, implicitly deactivate...\n"); | 410 | (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { |
411 | pr_debug("target active or w4 select, implicitly deactivate\n"); | ||
376 | 412 | ||
377 | rc = nci_request(ndev, nci_rf_deactivate_req, 0, | 413 | rc = nci_request(ndev, nci_rf_deactivate_req, 0, |
378 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); | 414 | msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); |
@@ -393,7 +429,8 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) | |||
393 | { | 429 | { |
394 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 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 | pr_err("unable to stop poll, since poll is not active\n"); | 434 | pr_err("unable to stop poll, since poll is not active\n"); |
398 | return; | 435 | return; |
399 | } | 436 | } |
@@ -406,10 +443,15 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, | |||
406 | __u32 protocol) | 443 | __u32 protocol) |
407 | { | 444 | { |
408 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 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 | pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); | 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 | pr_err("there is no available target to activate\n"); | 455 | pr_err("there is no available target to activate\n"); |
414 | return -EINVAL; | 456 | return -EINVAL; |
415 | } | 457 | } |
@@ -419,16 +461,47 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, | |||
419 | return -EBUSY; | 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 | pr_err("target does not support the requested protocol 0x%x\n", | 477 | pr_err("target does not support the requested protocol 0x%x\n", |
424 | protocol); | 478 | protocol); |
425 | return -EINVAL; | 479 | return -EINVAL; |
426 | } | 480 | } |
427 | 481 | ||
428 | ndev->target_active_prot = protocol; | 482 | if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { |
429 | ndev->target_available_prots = 0; | 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 | static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) | 507 | static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 8ec39464cea5..03e7b4626a3e 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -71,6 +71,20 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, | |||
71 | queue_work(ndev->tx_wq, &ndev->tx_work); | 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 | static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, | 88 | static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, |
75 | struct sk_buff *skb) | 89 | struct sk_buff *skb) |
76 | { | 90 | { |
@@ -86,12 +100,9 @@ static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, | |||
86 | } | 100 | } |
87 | 101 | ||
88 | static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, | 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 | nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); | 106 | nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); |
96 | data += 2; | 107 | data += 2; |
97 | 108 | ||
@@ -116,12 +127,9 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, | |||
116 | } | 127 | } |
117 | 128 | ||
118 | static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, | 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 | nfcb_poll->sensb_res_len = *data++; | 133 | nfcb_poll->sensb_res_len = *data++; |
126 | 134 | ||
127 | pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); | 135 | pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); |
@@ -133,12 +141,9 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, | |||
133 | } | 141 | } |
134 | 142 | ||
135 | static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, | 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 | nfcf_poll->bit_rate = *data++; | 147 | nfcf_poll->bit_rate = *data++; |
143 | nfcf_poll->sensf_res_len = *data++; | 148 | nfcf_poll->sensf_res_len = *data++; |
144 | 149 | ||
@@ -151,6 +156,172 @@ static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, | |||
151 | return data; | 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 | static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, | 325 | static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, |
155 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | 326 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) |
156 | { | 327 | { |
@@ -184,74 +355,32 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, | |||
184 | default: | 355 | default: |
185 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | 356 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", |
186 | ntf->activation_rf_tech_and_mode); | 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, | 364 | static void nci_target_auto_activated(struct nci_dev *ndev, |
194 | struct nci_rf_intf_activated_ntf *ntf) | 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) | 372 | rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, |
201 | nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK; | 373 | ntf->activation_rf_tech_and_mode, |
202 | else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) | 374 | &ntf->rf_tech_specific_params); |
203 | nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK; | 375 | if (rc) |
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"); | ||
209 | return; | 376 | return; |
210 | } | ||
211 | 377 | ||
212 | pr_debug("new target found, supported_protocols 0x%x\n", | 378 | target->idx = ntf->rf_discovery_id; |
213 | nfc_tgt.supported_protocols); | 379 | ndev->n_targets++; |
214 | |||
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 | } | ||
246 | 380 | ||
247 | ndev->target_available_prots = nfc_tgt.supported_protocols; | 381 | pr_debug("target_idx %d, n_targets %d\n", target->idx, ndev->n_targets); |
248 | ndev->max_data_pkt_payload_size = ntf->max_data_pkt_payload_size; | ||
249 | ndev->initial_num_credits = ntf->initial_num_credits; | ||
250 | 382 | ||
251 | /* set the available credits to initial value */ | 383 | nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets); |
252 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); | ||
253 | |||
254 | nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1); | ||
255 | } | 384 | } |
256 | 385 | ||
257 | static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | 386 | static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, |
@@ -259,9 +388,7 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
259 | { | 388 | { |
260 | struct nci_rf_intf_activated_ntf ntf; | 389 | struct nci_rf_intf_activated_ntf ntf; |
261 | __u8 *data = skb->data; | 390 | __u8 *data = skb->data; |
262 | int err = 0; | 391 | int err = NCI_STATUS_OK; |
263 | |||
264 | atomic_set(&ndev->state, NCI_POLL_ACTIVE); | ||
265 | 392 | ||
266 | ntf.rf_discovery_id = *data++; | 393 | ntf.rf_discovery_id = *data++; |
267 | ntf.rf_interface = *data++; | 394 | ntf.rf_interface = *data++; |
@@ -286,23 +413,24 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
286 | switch (ntf.activation_rf_tech_and_mode) { | 413 | switch (ntf.activation_rf_tech_and_mode) { |
287 | case NCI_NFC_A_PASSIVE_POLL_MODE: | 414 | case NCI_NFC_A_PASSIVE_POLL_MODE: |
288 | data = nci_extract_rf_params_nfca_passive_poll(ndev, | 415 | data = nci_extract_rf_params_nfca_passive_poll(ndev, |
289 | &ntf, data); | 416 | &(ntf.rf_tech_specific_params.nfca_poll), data); |
290 | break; | 417 | break; |
291 | 418 | ||
292 | case NCI_NFC_B_PASSIVE_POLL_MODE: | 419 | case NCI_NFC_B_PASSIVE_POLL_MODE: |
293 | data = nci_extract_rf_params_nfcb_passive_poll(ndev, | 420 | data = nci_extract_rf_params_nfcb_passive_poll(ndev, |
294 | &ntf, data); | 421 | &(ntf.rf_tech_specific_params.nfcb_poll), data); |
295 | break; | 422 | break; |
296 | 423 | ||
297 | case NCI_NFC_F_PASSIVE_POLL_MODE: | 424 | case NCI_NFC_F_PASSIVE_POLL_MODE: |
298 | data = nci_extract_rf_params_nfcf_passive_poll(ndev, | 425 | data = nci_extract_rf_params_nfcf_passive_poll(ndev, |
299 | &ntf, data); | 426 | &(ntf.rf_tech_specific_params.nfcf_poll), data); |
300 | break; | 427 | break; |
301 | 428 | ||
302 | default: | 429 | default: |
303 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | 430 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", |
304 | ntf.activation_rf_tech_and_mode); | 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 | ||
@@ -334,12 +462,30 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
334 | default: | 462 | default: |
335 | pr_err("unsupported rf_interface 0x%x\n", | 463 | pr_err("unsupported rf_interface 0x%x\n", |
336 | ntf.rf_interface); | 464 | ntf.rf_interface); |
337 | return; | 465 | err = NCI_STATUS_RF_PROTOCOL_ERROR; |
466 | break; | ||
338 | } | 467 | } |
339 | } | 468 | } |
340 | 469 | ||
341 | if (!err) | 470 | exit: |
342 | nci_target_found(ndev, &ntf); | 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 | static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, | 491 | static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, |
@@ -349,9 +495,6 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, | |||
349 | 495 | ||
350 | pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason); | 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 | /* drop tx data queue */ | 498 | /* drop tx data queue */ |
356 | skb_queue_purge(&ndev->tx_q); | 499 | skb_queue_purge(&ndev->tx_q); |
357 | 500 | ||
@@ -365,6 +508,8 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, | |||
365 | if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) | 508 | if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) |
366 | nci_data_exchange_complete(ndev, NULL, -EIO); | 509 | nci_data_exchange_complete(ndev, NULL, -EIO); |
367 | 510 | ||
511 | nci_clear_target_list(ndev); | ||
512 | atomic_set(&ndev->state, NCI_IDLE); | ||
368 | nci_req_complete(ndev, NCI_STATUS_OK); | 513 | nci_req_complete(ndev, NCI_STATUS_OK); |
369 | } | 514 | } |
370 | 515 | ||
@@ -386,10 +531,18 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
386 | nci_core_conn_credits_ntf_packet(ndev, skb); | 531 | nci_core_conn_credits_ntf_packet(ndev, skb); |
387 | break; | 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 | case NCI_OP_CORE_INTF_ERROR_NTF: | 538 | case NCI_OP_CORE_INTF_ERROR_NTF: |
390 | nci_core_conn_intf_error_ntf_packet(ndev, skb); | 539 | nci_core_conn_intf_error_ntf_packet(ndev, skb); |
391 | break; | 540 | break; |
392 | 541 | ||
542 | case NCI_OP_RF_DISCOVER_NTF: | ||
543 | nci_rf_discover_ntf_packet(ndev, skb); | ||
544 | break; | ||
545 | |||
393 | case NCI_OP_RF_INTF_ACTIVATED_NTF: | 546 | case NCI_OP_RF_INTF_ACTIVATED_NTF: |
394 | nci_rf_intf_activated_ntf_packet(ndev, skb); | 547 | nci_rf_intf_activated_ntf_packet(ndev, skb); |
395 | break; | 548 | break; |
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index cb8bce6899cf..aa63b1e99188 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c | |||
@@ -142,6 +142,18 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
142 | nci_req_complete(ndev, status); | 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 | static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, | 157 | static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, |
146 | struct sk_buff *skb) | 158 | struct sk_buff *skb) |
147 | { | 159 | { |
@@ -152,6 +164,7 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, | |||
152 | /* If target was active, complete the request only in deactivate_ntf */ | 164 | /* If target was active, complete the request only in deactivate_ntf */ |
153 | if ((status != NCI_STATUS_OK) || | 165 | if ((status != NCI_STATUS_OK) || |
154 | (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { | 166 | (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { |
167 | nci_clear_target_list(ndev); | ||
155 | atomic_set(&ndev->state, NCI_IDLE); | 168 | atomic_set(&ndev->state, NCI_IDLE); |
156 | nci_req_complete(ndev, status); | 169 | nci_req_complete(ndev, status); |
157 | } | 170 | } |
@@ -190,6 +203,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
190 | nci_rf_disc_rsp_packet(ndev, skb); | 203 | nci_rf_disc_rsp_packet(ndev, skb); |
191 | break; | 204 | break; |
192 | 205 | ||
206 | case NCI_OP_RF_DISCOVER_SELECT_RSP: | ||
207 | nci_rf_disc_select_rsp_packet(ndev, skb); | ||
208 | break; | ||
209 | |||
193 | case NCI_OP_RF_DEACTIVATE_RSP: | 210 | case NCI_OP_RF_DEACTIVATE_RSP: |
194 | nci_rf_deactivate_rsp_packet(ndev, skb); | 211 | nci_rf_deactivate_rsp_packet(ndev, skb); |
195 | break; | 212 | break; |