diff options
Diffstat (limited to 'net/nfc/core.c')
-rw-r--r-- | net/nfc/core.c | 157 |
1 files changed, 119 insertions, 38 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index 9f6ce011d35d..ff749794bc5b 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/nfc.h> | 30 | #include <linux/nfc.h> |
31 | 31 | ||
32 | #include <net/genetlink.h> | ||
33 | |||
32 | #include "nfc.h" | 34 | #include "nfc.h" |
33 | 35 | ||
34 | #define VERSION "0.1" | 36 | #define VERSION "0.1" |
@@ -121,14 +123,14 @@ error: | |||
121 | * The device remains polling for targets until a target is found or | 123 | * The device remains polling for targets until a target is found or |
122 | * the nfc_stop_poll function is called. | 124 | * the nfc_stop_poll function is called. |
123 | */ | 125 | */ |
124 | int nfc_start_poll(struct nfc_dev *dev, u32 protocols) | 126 | int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols) |
125 | { | 127 | { |
126 | int rc; | 128 | int rc; |
127 | 129 | ||
128 | pr_debug("dev_name=%s protocols=0x%x\n", | 130 | pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x\n", |
129 | dev_name(&dev->dev), protocols); | 131 | dev_name(&dev->dev), im_protocols, tm_protocols); |
130 | 132 | ||
131 | if (!protocols) | 133 | if (!im_protocols && !tm_protocols) |
132 | return -EINVAL; | 134 | return -EINVAL; |
133 | 135 | ||
134 | device_lock(&dev->dev); | 136 | device_lock(&dev->dev); |
@@ -143,9 +145,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols) | |||
143 | goto error; | 145 | goto error; |
144 | } | 146 | } |
145 | 147 | ||
146 | rc = dev->ops->start_poll(dev, protocols); | 148 | rc = dev->ops->start_poll(dev, im_protocols, tm_protocols); |
147 | if (!rc) | 149 | if (!rc) { |
148 | dev->polling = true; | 150 | dev->polling = true; |
151 | dev->rf_mode = NFC_RF_NONE; | ||
152 | } | ||
149 | 153 | ||
150 | error: | 154 | error: |
151 | device_unlock(&dev->dev); | 155 | device_unlock(&dev->dev); |
@@ -235,8 +239,10 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) | |||
235 | } | 239 | } |
236 | 240 | ||
237 | rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len); | 241 | rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len); |
238 | if (!rc) | 242 | if (!rc) { |
239 | dev->active_target = target; | 243 | dev->active_target = target; |
244 | dev->rf_mode = NFC_RF_INITIATOR; | ||
245 | } | ||
240 | 246 | ||
241 | error: | 247 | error: |
242 | device_unlock(&dev->dev); | 248 | device_unlock(&dev->dev); |
@@ -264,11 +270,6 @@ int nfc_dep_link_down(struct nfc_dev *dev) | |||
264 | goto error; | 270 | goto error; |
265 | } | 271 | } |
266 | 272 | ||
267 | if (dev->dep_rf_mode == NFC_RF_TARGET) { | ||
268 | rc = -EOPNOTSUPP; | ||
269 | goto error; | ||
270 | } | ||
271 | |||
272 | rc = dev->ops->dep_link_down(dev); | 273 | rc = dev->ops->dep_link_down(dev); |
273 | if (!rc) { | 274 | if (!rc) { |
274 | dev->dep_link_up = false; | 275 | dev->dep_link_up = false; |
@@ -286,7 +287,6 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx, | |||
286 | u8 comm_mode, u8 rf_mode) | 287 | u8 comm_mode, u8 rf_mode) |
287 | { | 288 | { |
288 | dev->dep_link_up = true; | 289 | dev->dep_link_up = true; |
289 | dev->dep_rf_mode = rf_mode; | ||
290 | 290 | ||
291 | nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode); | 291 | nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode); |
292 | 292 | ||
@@ -330,6 +330,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) | |||
330 | rc = dev->ops->activate_target(dev, target, protocol); | 330 | rc = dev->ops->activate_target(dev, target, protocol); |
331 | if (!rc) { | 331 | if (!rc) { |
332 | dev->active_target = target; | 332 | dev->active_target = target; |
333 | dev->rf_mode = NFC_RF_INITIATOR; | ||
333 | 334 | ||
334 | if (dev->ops->check_presence) | 335 | if (dev->ops->check_presence) |
335 | mod_timer(&dev->check_pres_timer, jiffies + | 336 | mod_timer(&dev->check_pres_timer, jiffies + |
@@ -409,27 +410,30 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, | |||
409 | goto error; | 410 | goto error; |
410 | } | 411 | } |
411 | 412 | ||
412 | if (dev->active_target == NULL) { | 413 | if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) { |
413 | rc = -ENOTCONN; | 414 | if (dev->active_target->idx != target_idx) { |
414 | kfree_skb(skb); | 415 | rc = -EADDRNOTAVAIL; |
415 | goto error; | 416 | kfree_skb(skb); |
416 | } | 417 | goto error; |
418 | } | ||
417 | 419 | ||
418 | if (dev->active_target->idx != target_idx) { | 420 | if (dev->ops->check_presence) |
419 | rc = -EADDRNOTAVAIL; | 421 | del_timer_sync(&dev->check_pres_timer); |
422 | |||
423 | rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb, | ||
424 | cb_context); | ||
425 | |||
426 | if (!rc && dev->ops->check_presence) | ||
427 | mod_timer(&dev->check_pres_timer, jiffies + | ||
428 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); | ||
429 | } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) { | ||
430 | rc = dev->ops->tm_send(dev, skb); | ||
431 | } else { | ||
432 | rc = -ENOTCONN; | ||
420 | kfree_skb(skb); | 433 | kfree_skb(skb); |
421 | goto error; | 434 | goto error; |
422 | } | 435 | } |
423 | 436 | ||
424 | if (dev->ops->check_presence) | ||
425 | del_timer_sync(&dev->check_pres_timer); | ||
426 | |||
427 | rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb, | ||
428 | cb_context); | ||
429 | |||
430 | if (!rc && dev->ops->check_presence) | ||
431 | mod_timer(&dev->check_pres_timer, jiffies + | ||
432 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); | ||
433 | 437 | ||
434 | error: | 438 | error: |
435 | device_unlock(&dev->dev); | 439 | device_unlock(&dev->dev); |
@@ -447,6 +451,63 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len) | |||
447 | } | 451 | } |
448 | EXPORT_SYMBOL(nfc_set_remote_general_bytes); | 452 | EXPORT_SYMBOL(nfc_set_remote_general_bytes); |
449 | 453 | ||
454 | u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len) | ||
455 | { | ||
456 | pr_debug("dev_name=%s\n", dev_name(&dev->dev)); | ||
457 | |||
458 | return nfc_llcp_general_bytes(dev, gb_len); | ||
459 | } | ||
460 | EXPORT_SYMBOL(nfc_get_local_general_bytes); | ||
461 | |||
462 | int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb) | ||
463 | { | ||
464 | /* Only LLCP target mode for now */ | ||
465 | if (dev->dep_link_up == false) { | ||
466 | kfree_skb(skb); | ||
467 | return -ENOLINK; | ||
468 | } | ||
469 | |||
470 | return nfc_llcp_data_received(dev, skb); | ||
471 | } | ||
472 | EXPORT_SYMBOL(nfc_tm_data_received); | ||
473 | |||
474 | int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode, | ||
475 | u8 *gb, size_t gb_len) | ||
476 | { | ||
477 | int rc; | ||
478 | |||
479 | device_lock(&dev->dev); | ||
480 | |||
481 | dev->polling = false; | ||
482 | |||
483 | if (gb != NULL) { | ||
484 | rc = nfc_set_remote_general_bytes(dev, gb, gb_len); | ||
485 | if (rc < 0) | ||
486 | goto out; | ||
487 | } | ||
488 | |||
489 | dev->rf_mode = NFC_RF_TARGET; | ||
490 | |||
491 | if (protocol == NFC_PROTO_NFC_DEP_MASK) | ||
492 | nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET); | ||
493 | |||
494 | rc = nfc_genl_tm_activated(dev, protocol); | ||
495 | |||
496 | out: | ||
497 | device_unlock(&dev->dev); | ||
498 | |||
499 | return rc; | ||
500 | } | ||
501 | EXPORT_SYMBOL(nfc_tm_activated); | ||
502 | |||
503 | int nfc_tm_deactivated(struct nfc_dev *dev) | ||
504 | { | ||
505 | dev->dep_link_up = false; | ||
506 | |||
507 | return nfc_genl_tm_deactivated(dev); | ||
508 | } | ||
509 | EXPORT_SYMBOL(nfc_tm_deactivated); | ||
510 | |||
450 | /** | 511 | /** |
451 | * nfc_alloc_send_skb - allocate a skb for data exchange responses | 512 | * nfc_alloc_send_skb - allocate a skb for data exchange responses |
452 | * | 513 | * |
@@ -501,6 +562,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); | |||
501 | * The device driver must call this function when one or many nfc targets | 562 | * The device driver must call this function when one or many nfc targets |
502 | * are found. After calling this function, the device driver must stop | 563 | * are found. After calling this function, the device driver must stop |
503 | * polling for targets. | 564 | * polling for targets. |
565 | * NOTE: This function can be called with targets=NULL and n_targets=0 to | ||
566 | * notify a driver error, meaning that the polling operation cannot complete. | ||
504 | * IMPORTANT: this function must not be called from an atomic context. | 567 | * 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 | 568 | * 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. | 569 | * the NFC Core to call other nfc ops entry point concurrently. |
@@ -512,23 +575,33 @@ int nfc_targets_found(struct nfc_dev *dev, | |||
512 | 575 | ||
513 | pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); | 576 | pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); |
514 | 577 | ||
515 | dev->polling = false; | ||
516 | |||
517 | for (i = 0; i < n_targets; i++) | 578 | for (i = 0; i < n_targets; i++) |
518 | targets[i].idx = dev->target_next_idx++; | 579 | targets[i].idx = dev->target_next_idx++; |
519 | 580 | ||
520 | device_lock(&dev->dev); | 581 | device_lock(&dev->dev); |
521 | 582 | ||
583 | if (dev->polling == false) { | ||
584 | device_unlock(&dev->dev); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | dev->polling = false; | ||
589 | |||
522 | dev->targets_generation++; | 590 | dev->targets_generation++; |
523 | 591 | ||
524 | kfree(dev->targets); | 592 | kfree(dev->targets); |
525 | dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), | 593 | dev->targets = NULL; |
526 | GFP_ATOMIC); | ||
527 | 594 | ||
528 | if (!dev->targets) { | 595 | if (targets) { |
529 | dev->n_targets = 0; | 596 | dev->targets = kmemdup(targets, |
530 | device_unlock(&dev->dev); | 597 | n_targets * sizeof(struct nfc_target), |
531 | return -ENOMEM; | 598 | GFP_ATOMIC); |
599 | |||
600 | if (!dev->targets) { | ||
601 | dev->n_targets = 0; | ||
602 | device_unlock(&dev->dev); | ||
603 | return -ENOMEM; | ||
604 | } | ||
532 | } | 605 | } |
533 | 606 | ||
534 | dev->n_targets = n_targets; | 607 | dev->n_targets = n_targets; |
@@ -592,6 +665,12 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | |||
592 | } | 665 | } |
593 | EXPORT_SYMBOL(nfc_target_lost); | 666 | EXPORT_SYMBOL(nfc_target_lost); |
594 | 667 | ||
668 | inline void nfc_driver_failure(struct nfc_dev *dev, int err) | ||
669 | { | ||
670 | nfc_targets_found(dev, NULL, 0); | ||
671 | } | ||
672 | EXPORT_SYMBOL(nfc_driver_failure); | ||
673 | |||
595 | static void nfc_release(struct device *d) | 674 | static void nfc_release(struct device *d) |
596 | { | 675 | { |
597 | struct nfc_dev *dev = to_nfc_dev(d); | 676 | struct nfc_dev *dev = to_nfc_dev(d); |
@@ -678,7 +757,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
678 | struct nfc_dev *dev; | 757 | struct nfc_dev *dev; |
679 | 758 | ||
680 | if (!ops->start_poll || !ops->stop_poll || !ops->activate_target || | 759 | if (!ops->start_poll || !ops->stop_poll || !ops->activate_target || |
681 | !ops->deactivate_target || !ops->data_exchange) | 760 | !ops->deactivate_target || !ops->im_transceive) |
682 | return NULL; | 761 | return NULL; |
683 | 762 | ||
684 | if (!supported_protocols) | 763 | if (!supported_protocols) |
@@ -847,3 +926,5 @@ MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); | |||
847 | MODULE_DESCRIPTION("NFC Core ver " VERSION); | 926 | MODULE_DESCRIPTION("NFC Core ver " VERSION); |
848 | MODULE_VERSION(VERSION); | 927 | MODULE_VERSION(VERSION); |
849 | MODULE_LICENSE("GPL"); | 928 | MODULE_LICENSE("GPL"); |
929 | MODULE_ALIAS_NETPROTO(PF_NFC); | ||
930 | MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME); | ||