diff options
Diffstat (limited to 'net/nfc/core.c')
-rw-r--r-- | net/nfc/core.c | 112 |
1 files changed, 85 insertions, 27 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index 3192c3f589ee..9f6ce011d35d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -97,7 +97,7 @@ int nfc_dev_down(struct nfc_dev *dev) | |||
97 | goto error; | 97 | goto error; |
98 | } | 98 | } |
99 | 99 | ||
100 | if (dev->polling || dev->activated_target_idx != NFC_TARGET_IDX_NONE) { | 100 | if (dev->polling || dev->active_target) { |
101 | rc = -EBUSY; | 101 | rc = -EBUSY; |
102 | goto error; | 102 | goto error; |
103 | } | 103 | } |
@@ -183,11 +183,27 @@ error: | |||
183 | return rc; | 183 | return rc; |
184 | } | 184 | } |
185 | 185 | ||
186 | static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) | ||
187 | { | ||
188 | int i; | ||
189 | |||
190 | if (dev->n_targets == 0) | ||
191 | return NULL; | ||
192 | |||
193 | for (i = 0; i < dev->n_targets ; i++) { | ||
194 | if (dev->targets[i].idx == target_idx) | ||
195 | return &dev->targets[i]; | ||
196 | } | ||
197 | |||
198 | return NULL; | ||
199 | } | ||
200 | |||
186 | int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) | 201 | int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) |
187 | { | 202 | { |
188 | int rc = 0; | 203 | int rc = 0; |
189 | u8 *gb; | 204 | u8 *gb; |
190 | size_t gb_len; | 205 | size_t gb_len; |
206 | struct nfc_target *target; | ||
191 | 207 | ||
192 | pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode); | 208 | pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode); |
193 | 209 | ||
@@ -212,9 +228,15 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) | |||
212 | goto error; | 228 | goto error; |
213 | } | 229 | } |
214 | 230 | ||
215 | rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len); | 231 | target = nfc_find_target(dev, target_index); |
232 | if (target == NULL) { | ||
233 | rc = -ENOTCONN; | ||
234 | goto error; | ||
235 | } | ||
236 | |||
237 | rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len); | ||
216 | if (!rc) | 238 | if (!rc) |
217 | dev->activated_target_idx = target_index; | 239 | dev->active_target = target; |
218 | 240 | ||
219 | error: | 241 | error: |
220 | device_unlock(&dev->dev); | 242 | device_unlock(&dev->dev); |
@@ -250,7 +272,7 @@ int nfc_dep_link_down(struct nfc_dev *dev) | |||
250 | rc = dev->ops->dep_link_down(dev); | 272 | rc = dev->ops->dep_link_down(dev); |
251 | if (!rc) { | 273 | if (!rc) { |
252 | dev->dep_link_up = false; | 274 | dev->dep_link_up = false; |
253 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | 275 | dev->active_target = NULL; |
254 | nfc_llcp_mac_is_down(dev); | 276 | nfc_llcp_mac_is_down(dev); |
255 | nfc_genl_dep_link_down_event(dev); | 277 | nfc_genl_dep_link_down_event(dev); |
256 | } | 278 | } |
@@ -282,6 +304,7 @@ EXPORT_SYMBOL(nfc_dep_link_is_up); | |||
282 | int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) | 304 | int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) |
283 | { | 305 | { |
284 | int rc; | 306 | int rc; |
307 | struct nfc_target *target; | ||
285 | 308 | ||
286 | pr_debug("dev_name=%s target_idx=%u protocol=%u\n", | 309 | pr_debug("dev_name=%s target_idx=%u protocol=%u\n", |
287 | dev_name(&dev->dev), target_idx, protocol); | 310 | dev_name(&dev->dev), target_idx, protocol); |
@@ -293,9 +316,20 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) | |||
293 | goto error; | 316 | goto error; |
294 | } | 317 | } |
295 | 318 | ||
296 | rc = dev->ops->activate_target(dev, target_idx, protocol); | 319 | if (dev->active_target) { |
320 | rc = -EBUSY; | ||
321 | goto error; | ||
322 | } | ||
323 | |||
324 | target = nfc_find_target(dev, target_idx); | ||
325 | if (target == NULL) { | ||
326 | rc = -ENOTCONN; | ||
327 | goto error; | ||
328 | } | ||
329 | |||
330 | rc = dev->ops->activate_target(dev, target, protocol); | ||
297 | if (!rc) { | 331 | if (!rc) { |
298 | dev->activated_target_idx = target_idx; | 332 | dev->active_target = target; |
299 | 333 | ||
300 | if (dev->ops->check_presence) | 334 | if (dev->ops->check_presence) |
301 | mod_timer(&dev->check_pres_timer, jiffies + | 335 | mod_timer(&dev->check_pres_timer, jiffies + |
@@ -327,11 +361,21 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) | |||
327 | goto error; | 361 | goto error; |
328 | } | 362 | } |
329 | 363 | ||
364 | if (dev->active_target == NULL) { | ||
365 | rc = -ENOTCONN; | ||
366 | goto error; | ||
367 | } | ||
368 | |||
369 | if (dev->active_target->idx != target_idx) { | ||
370 | rc = -ENOTCONN; | ||
371 | goto error; | ||
372 | } | ||
373 | |||
330 | if (dev->ops->check_presence) | 374 | if (dev->ops->check_presence) |
331 | del_timer_sync(&dev->check_pres_timer); | 375 | del_timer_sync(&dev->check_pres_timer); |
332 | 376 | ||
333 | dev->ops->deactivate_target(dev, target_idx); | 377 | dev->ops->deactivate_target(dev, dev->active_target); |
334 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | 378 | dev->active_target = NULL; |
335 | 379 | ||
336 | error: | 380 | error: |
337 | device_unlock(&dev->dev); | 381 | device_unlock(&dev->dev); |
@@ -365,13 +409,13 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, | |||
365 | goto error; | 409 | goto error; |
366 | } | 410 | } |
367 | 411 | ||
368 | if (dev->activated_target_idx == NFC_TARGET_IDX_NONE) { | 412 | if (dev->active_target == NULL) { |
369 | rc = -ENOTCONN; | 413 | rc = -ENOTCONN; |
370 | kfree_skb(skb); | 414 | kfree_skb(skb); |
371 | goto error; | 415 | goto error; |
372 | } | 416 | } |
373 | 417 | ||
374 | if (target_idx != dev->activated_target_idx) { | 418 | if (dev->active_target->idx != target_idx) { |
375 | rc = -EADDRNOTAVAIL; | 419 | rc = -EADDRNOTAVAIL; |
376 | kfree_skb(skb); | 420 | kfree_skb(skb); |
377 | goto error; | 421 | goto error; |
@@ -380,7 +424,8 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, | |||
380 | if (dev->ops->check_presence) | 424 | if (dev->ops->check_presence) |
381 | del_timer_sync(&dev->check_pres_timer); | 425 | del_timer_sync(&dev->check_pres_timer); |
382 | 426 | ||
383 | rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); | 427 | rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb, |
428 | cb_context); | ||
384 | 429 | ||
385 | if (!rc && dev->ops->check_presence) | 430 | if (!rc && dev->ops->check_presence) |
386 | mod_timer(&dev->check_pres_timer, jiffies + | 431 | mod_timer(&dev->check_pres_timer, jiffies + |
@@ -456,6 +501,9 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); | |||
456 | * The device driver must call this function when one or many nfc targets | 501 | * The device driver must call this function when one or many nfc targets |
457 | * are found. After calling this function, the device driver must stop | 502 | * are found. After calling this function, the device driver must stop |
458 | * polling for targets. | 503 | * polling for targets. |
504 | * IMPORTANT: this function must not be called from an atomic context. | ||
505 | * In addition, it must also not be called from a context that would prevent | ||
506 | * the NFC Core to call other nfc ops entry point concurrently. | ||
459 | */ | 507 | */ |
460 | int nfc_targets_found(struct nfc_dev *dev, | 508 | int nfc_targets_found(struct nfc_dev *dev, |
461 | struct nfc_target *targets, int n_targets) | 509 | struct nfc_target *targets, int n_targets) |
@@ -469,7 +517,7 @@ int nfc_targets_found(struct nfc_dev *dev, | |||
469 | for (i = 0; i < n_targets; i++) | 517 | for (i = 0; i < n_targets; i++) |
470 | targets[i].idx = dev->target_next_idx++; | 518 | targets[i].idx = dev->target_next_idx++; |
471 | 519 | ||
472 | spin_lock_bh(&dev->targets_lock); | 520 | device_lock(&dev->dev); |
473 | 521 | ||
474 | dev->targets_generation++; | 522 | dev->targets_generation++; |
475 | 523 | ||
@@ -479,12 +527,12 @@ int nfc_targets_found(struct nfc_dev *dev, | |||
479 | 527 | ||
480 | if (!dev->targets) { | 528 | if (!dev->targets) { |
481 | dev->n_targets = 0; | 529 | dev->n_targets = 0; |
482 | spin_unlock_bh(&dev->targets_lock); | 530 | device_unlock(&dev->dev); |
483 | return -ENOMEM; | 531 | return -ENOMEM; |
484 | } | 532 | } |
485 | 533 | ||
486 | dev->n_targets = n_targets; | 534 | dev->n_targets = n_targets; |
487 | spin_unlock_bh(&dev->targets_lock); | 535 | device_unlock(&dev->dev); |
488 | 536 | ||
489 | nfc_genl_targets_found(dev); | 537 | nfc_genl_targets_found(dev); |
490 | 538 | ||
@@ -492,6 +540,18 @@ int nfc_targets_found(struct nfc_dev *dev, | |||
492 | } | 540 | } |
493 | EXPORT_SYMBOL(nfc_targets_found); | 541 | EXPORT_SYMBOL(nfc_targets_found); |
494 | 542 | ||
543 | /** | ||
544 | * nfc_target_lost - inform that an activated target went out of field | ||
545 | * | ||
546 | * @dev: The nfc device that had the activated target in field | ||
547 | * @target_idx: the nfc index of the target | ||
548 | * | ||
549 | * The device driver must call this function when the activated target | ||
550 | * goes out of the field. | ||
551 | * IMPORTANT: this function must not be called from an atomic context. | ||
552 | * In addition, it must also not be called from a context that would prevent | ||
553 | * the NFC Core to call other nfc ops entry point concurrently. | ||
554 | */ | ||
495 | int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | 555 | int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) |
496 | { | 556 | { |
497 | struct nfc_target *tg; | 557 | struct nfc_target *tg; |
@@ -499,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | |||
499 | 559 | ||
500 | pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx); | 560 | pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx); |
501 | 561 | ||
502 | spin_lock_bh(&dev->targets_lock); | 562 | device_lock(&dev->dev); |
503 | 563 | ||
504 | for (i = 0; i < dev->n_targets; i++) { | 564 | for (i = 0; i < dev->n_targets; i++) { |
505 | tg = &dev->targets[i]; | 565 | tg = &dev->targets[i]; |
@@ -508,13 +568,13 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | |||
508 | } | 568 | } |
509 | 569 | ||
510 | if (i == dev->n_targets) { | 570 | if (i == dev->n_targets) { |
511 | spin_unlock_bh(&dev->targets_lock); | 571 | device_unlock(&dev->dev); |
512 | return -EINVAL; | 572 | return -EINVAL; |
513 | } | 573 | } |
514 | 574 | ||
515 | dev->targets_generation++; | 575 | dev->targets_generation++; |
516 | dev->n_targets--; | 576 | dev->n_targets--; |
517 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | 577 | dev->active_target = NULL; |
518 | 578 | ||
519 | if (dev->n_targets) { | 579 | if (dev->n_targets) { |
520 | memcpy(&dev->targets[i], &dev->targets[i + 1], | 580 | memcpy(&dev->targets[i], &dev->targets[i + 1], |
@@ -524,7 +584,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | |||
524 | dev->targets = NULL; | 584 | dev->targets = NULL; |
525 | } | 585 | } |
526 | 586 | ||
527 | spin_unlock_bh(&dev->targets_lock); | 587 | device_unlock(&dev->dev); |
528 | 588 | ||
529 | nfc_genl_target_lost(dev, target_idx); | 589 | nfc_genl_target_lost(dev, target_idx); |
530 | 590 | ||
@@ -556,15 +616,16 @@ static void nfc_check_pres_work(struct work_struct *work) | |||
556 | 616 | ||
557 | device_lock(&dev->dev); | 617 | device_lock(&dev->dev); |
558 | 618 | ||
559 | if (dev->activated_target_idx != NFC_TARGET_IDX_NONE && | 619 | if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) { |
560 | timer_pending(&dev->check_pres_timer) == 0) { | 620 | rc = dev->ops->check_presence(dev, dev->active_target); |
561 | rc = dev->ops->check_presence(dev, dev->activated_target_idx); | ||
562 | if (!rc) { | 621 | if (!rc) { |
563 | mod_timer(&dev->check_pres_timer, jiffies + | 622 | mod_timer(&dev->check_pres_timer, jiffies + |
564 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); | 623 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); |
565 | } else { | 624 | } else { |
566 | nfc_target_lost(dev, dev->activated_target_idx); | 625 | u32 active_target_idx = dev->active_target->idx; |
567 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | 626 | device_unlock(&dev->dev); |
627 | nfc_target_lost(dev, active_target_idx); | ||
628 | return; | ||
568 | } | 629 | } |
569 | } | 630 | } |
570 | 631 | ||
@@ -637,14 +698,12 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
637 | dev->tx_headroom = tx_headroom; | 698 | dev->tx_headroom = tx_headroom; |
638 | dev->tx_tailroom = tx_tailroom; | 699 | dev->tx_tailroom = tx_tailroom; |
639 | 700 | ||
640 | spin_lock_init(&dev->targets_lock); | ||
641 | nfc_genl_data_init(&dev->genl_data); | 701 | nfc_genl_data_init(&dev->genl_data); |
642 | 702 | ||
703 | |||
643 | /* first generation must not be 0 */ | 704 | /* first generation must not be 0 */ |
644 | dev->targets_generation = 1; | 705 | dev->targets_generation = 1; |
645 | 706 | ||
646 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | ||
647 | |||
648 | if (ops->check_presence) { | 707 | if (ops->check_presence) { |
649 | char name[32]; | 708 | char name[32]; |
650 | init_timer(&dev->check_pres_timer); | 709 | init_timer(&dev->check_pres_timer); |
@@ -662,7 +721,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
662 | } | 721 | } |
663 | } | 722 | } |
664 | 723 | ||
665 | |||
666 | return dev; | 724 | return dev; |
667 | } | 725 | } |
668 | EXPORT_SYMBOL(nfc_allocate_device); | 726 | EXPORT_SYMBOL(nfc_allocate_device); |