diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-09-28 11:11:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-09-28 11:11:16 -0400 |
commit | c487606f835a93a725bac1aefd536be98f22474d (patch) | |
tree | c77571a519905945e24a9ea6e4e44d9032fd527d /net/nfc | |
parent | d9f72f359e00a45a6cd7cc2d5121b04b9dc927e1 (diff) | |
parent | 97ea6d0f3eb019891038cd2dfddb749d6bf219be (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
net/nfc/netlink.c
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/core.c | 13 | ||||
-rw-r--r-- | net/nfc/hci/Makefile | 4 | ||||
-rw-r--r-- | net/nfc/hci/command.c | 45 | ||||
-rw-r--r-- | net/nfc/hci/core.c | 336 | ||||
-rw-r--r-- | net/nfc/hci/hci.h | 15 | ||||
-rw-r--r-- | net/nfc/hci/hcp.c | 6 | ||||
-rw-r--r-- | net/nfc/hci/llc.c | 170 | ||||
-rw-r--r-- | net/nfc/hci/llc.h | 69 | ||||
-rw-r--r-- | net/nfc/hci/llc_nop.c | 99 | ||||
-rw-r--r-- | net/nfc/hci/llc_shdlc.c (renamed from net/nfc/hci/shdlc.c) | 544 | ||||
-rw-r--r-- | net/nfc/llcp/commands.c | 2 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 131 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 6 | ||||
-rw-r--r-- | net/nfc/llcp/sock.c | 93 | ||||
-rw-r--r-- | net/nfc/nci/core.c | 91 | ||||
-rw-r--r-- | net/nfc/nci/ntf.c | 52 | ||||
-rw-r--r-- | net/nfc/nci/rsp.c | 14 | ||||
-rw-r--r-- | net/nfc/netlink.c | 46 |
18 files changed, 1157 insertions, 579 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index ff749794bc5b..c9eacc1f145f 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -679,7 +679,7 @@ static void nfc_release(struct device *d) | |||
679 | 679 | ||
680 | if (dev->ops->check_presence) { | 680 | if (dev->ops->check_presence) { |
681 | del_timer_sync(&dev->check_pres_timer); | 681 | del_timer_sync(&dev->check_pres_timer); |
682 | destroy_workqueue(dev->check_pres_wq); | 682 | cancel_work_sync(&dev->check_pres_work); |
683 | } | 683 | } |
684 | 684 | ||
685 | nfc_genl_data_exit(&dev->genl_data); | 685 | nfc_genl_data_exit(&dev->genl_data); |
@@ -715,7 +715,7 @@ static void nfc_check_pres_timeout(unsigned long data) | |||
715 | { | 715 | { |
716 | struct nfc_dev *dev = (struct nfc_dev *)data; | 716 | struct nfc_dev *dev = (struct nfc_dev *)data; |
717 | 717 | ||
718 | queue_work(dev->check_pres_wq, &dev->check_pres_work); | 718 | queue_work(system_nrt_wq, &dev->check_pres_work); |
719 | } | 719 | } |
720 | 720 | ||
721 | struct class nfc_class = { | 721 | struct class nfc_class = { |
@@ -784,20 +784,11 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
784 | dev->targets_generation = 1; | 784 | dev->targets_generation = 1; |
785 | 785 | ||
786 | if (ops->check_presence) { | 786 | if (ops->check_presence) { |
787 | char name[32]; | ||
788 | init_timer(&dev->check_pres_timer); | 787 | init_timer(&dev->check_pres_timer); |
789 | dev->check_pres_timer.data = (unsigned long)dev; | 788 | dev->check_pres_timer.data = (unsigned long)dev; |
790 | dev->check_pres_timer.function = nfc_check_pres_timeout; | 789 | dev->check_pres_timer.function = nfc_check_pres_timeout; |
791 | 790 | ||
792 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); | 791 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); |
793 | snprintf(name, sizeof(name), "nfc%d_check_pres_wq", dev->idx); | ||
794 | dev->check_pres_wq = alloc_workqueue(name, WQ_NON_REENTRANT | | ||
795 | WQ_UNBOUND | | ||
796 | WQ_MEM_RECLAIM, 1); | ||
797 | if (dev->check_pres_wq == NULL) { | ||
798 | kfree(dev); | ||
799 | return NULL; | ||
800 | } | ||
801 | } | 792 | } |
802 | 793 | ||
803 | return dev; | 794 | return dev; |
diff --git a/net/nfc/hci/Makefile b/net/nfc/hci/Makefile index f9c44b2fb065..c5dbb6891b24 100644 --- a/net/nfc/hci/Makefile +++ b/net/nfc/hci/Makefile | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_NFC_HCI) += hci.o | 5 | obj-$(CONFIG_NFC_HCI) += hci.o |
6 | 6 | ||
7 | hci-y := core.o hcp.o command.o | 7 | hci-y := core.o hcp.o command.o llc.o llc_nop.o |
8 | hci-$(CONFIG_NFC_SHDLC) += shdlc.o | 8 | hci-$(CONFIG_NFC_SHDLC) += llc_shdlc.o |
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 46362ef979db..71c6a7086b8f 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
@@ -28,10 +28,29 @@ | |||
28 | 28 | ||
29 | #include "hci.h" | 29 | #include "hci.h" |
30 | 30 | ||
31 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, | 31 | static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, |
32 | struct sk_buff *skb, void *cb_data) | 32 | const u8 *param, size_t param_len, |
33 | data_exchange_cb_t cb, void *cb_context) | ||
33 | { | 34 | { |
34 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; | 35 | pr_debug("exec cmd async through pipe=%d, cmd=%d, plen=%zd\n", pipe, |
36 | cmd, param_len); | ||
37 | |||
38 | /* TODO: Define hci cmd execution delay. Should it be the same | ||
39 | * for all commands? | ||
40 | */ | ||
41 | return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_COMMAND, cmd, | ||
42 | param, param_len, cb, cb_context, 3000); | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * HCI command execution completion callback. | ||
47 | * err will be a standard linux error (may be converted from HCI response) | ||
48 | * skb contains the response data and must be disposed, or may be NULL if | ||
49 | * an error occured | ||
50 | */ | ||
51 | static void nfc_hci_execute_cb(void *context, struct sk_buff *skb, int err) | ||
52 | { | ||
53 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)context; | ||
35 | 54 | ||
36 | pr_debug("HCI Cmd completed with result=%d\n", err); | 55 | pr_debug("HCI Cmd completed with result=%d\n", err); |
37 | 56 | ||
@@ -55,7 +74,8 @@ static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, | |||
55 | hcp_ew.exec_complete = false; | 74 | hcp_ew.exec_complete = false; |
56 | hcp_ew.result_skb = NULL; | 75 | hcp_ew.result_skb = NULL; |
57 | 76 | ||
58 | pr_debug("through pipe=%d, cmd=%d, plen=%zd\n", pipe, cmd, param_len); | 77 | pr_debug("exec cmd sync through pipe=%d, cmd=%d, plen=%zd\n", pipe, |
78 | cmd, param_len); | ||
59 | 79 | ||
60 | /* TODO: Define hci cmd execution delay. Should it be the same | 80 | /* TODO: Define hci cmd execution delay. Should it be the same |
61 | * for all commands? | 81 | * for all commands? |
@@ -133,6 +153,23 @@ int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | |||
133 | } | 153 | } |
134 | EXPORT_SYMBOL(nfc_hci_send_cmd); | 154 | EXPORT_SYMBOL(nfc_hci_send_cmd); |
135 | 155 | ||
156 | int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | ||
157 | const u8 *param, size_t param_len, | ||
158 | data_exchange_cb_t cb, void *cb_context) | ||
159 | { | ||
160 | u8 pipe; | ||
161 | |||
162 | pr_debug("\n"); | ||
163 | |||
164 | pipe = hdev->gate2pipe[gate]; | ||
165 | if (pipe == NFC_HCI_INVALID_PIPE) | ||
166 | return -EADDRNOTAVAIL; | ||
167 | |||
168 | return nfc_hci_execute_cmd_async(hdev, pipe, cmd, param, param_len, | ||
169 | cb, cb_context); | ||
170 | } | ||
171 | EXPORT_SYMBOL(nfc_hci_send_cmd_async); | ||
172 | |||
136 | int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, | 173 | int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, |
137 | const u8 *param, size_t param_len) | 174 | const u8 *param, size_t param_len) |
138 | { | 175 | { |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 1ac7b3fac6c9..d378d93de62e 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <net/nfc/nfc.h> | 27 | #include <net/nfc/nfc.h> |
28 | #include <net/nfc/hci.h> | 28 | #include <net/nfc/hci.h> |
29 | #include <net/nfc/llc.h> | ||
29 | 30 | ||
30 | #include "hci.h" | 31 | #include "hci.h" |
31 | 32 | ||
@@ -57,12 +58,11 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) | |||
57 | if (hdev->cmd_pending_msg) { | 58 | if (hdev->cmd_pending_msg) { |
58 | if (timer_pending(&hdev->cmd_timer) == 0) { | 59 | if (timer_pending(&hdev->cmd_timer) == 0) { |
59 | if (hdev->cmd_pending_msg->cb) | 60 | if (hdev->cmd_pending_msg->cb) |
60 | hdev->cmd_pending_msg->cb(hdev, | 61 | hdev->cmd_pending_msg->cb(hdev-> |
61 | -ETIME, | ||
62 | NULL, | ||
63 | hdev-> | ||
64 | cmd_pending_msg-> | 62 | cmd_pending_msg-> |
65 | cb_context); | 63 | cb_context, |
64 | NULL, | ||
65 | -ETIME); | ||
66 | kfree(hdev->cmd_pending_msg); | 66 | kfree(hdev->cmd_pending_msg); |
67 | hdev->cmd_pending_msg = NULL; | 67 | hdev->cmd_pending_msg = NULL; |
68 | } else | 68 | } else |
@@ -78,12 +78,12 @@ next_msg: | |||
78 | 78 | ||
79 | pr_debug("msg_tx_queue has a cmd to send\n"); | 79 | pr_debug("msg_tx_queue has a cmd to send\n"); |
80 | while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { | 80 | while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { |
81 | r = hdev->ops->xmit(hdev, skb); | 81 | r = nfc_llc_xmit_from_hci(hdev->llc, skb); |
82 | if (r < 0) { | 82 | if (r < 0) { |
83 | kfree_skb(skb); | 83 | kfree_skb(skb); |
84 | skb_queue_purge(&msg->msg_frags); | 84 | skb_queue_purge(&msg->msg_frags); |
85 | if (msg->cb) | 85 | if (msg->cb) |
86 | msg->cb(hdev, r, NULL, msg->cb_context); | 86 | msg->cb(msg->cb_context, NULL, r); |
87 | kfree(msg); | 87 | kfree(msg); |
88 | break; | 88 | break; |
89 | } | 89 | } |
@@ -133,15 +133,15 @@ static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, | |||
133 | del_timer_sync(&hdev->cmd_timer); | 133 | del_timer_sync(&hdev->cmd_timer); |
134 | 134 | ||
135 | if (hdev->cmd_pending_msg->cb) | 135 | if (hdev->cmd_pending_msg->cb) |
136 | hdev->cmd_pending_msg->cb(hdev, err, skb, | 136 | hdev->cmd_pending_msg->cb(hdev->cmd_pending_msg->cb_context, |
137 | hdev->cmd_pending_msg->cb_context); | 137 | skb, err); |
138 | else | 138 | else |
139 | kfree_skb(skb); | 139 | kfree_skb(skb); |
140 | 140 | ||
141 | kfree(hdev->cmd_pending_msg); | 141 | kfree(hdev->cmd_pending_msg); |
142 | hdev->cmd_pending_msg = NULL; | 142 | hdev->cmd_pending_msg = NULL; |
143 | 143 | ||
144 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 144 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
145 | } | 145 | } |
146 | 146 | ||
147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | 147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, |
@@ -326,7 +326,7 @@ static void nfc_hci_cmd_timeout(unsigned long data) | |||
326 | { | 326 | { |
327 | struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; | 327 | struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; |
328 | 328 | ||
329 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 329 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
330 | } | 330 | } |
331 | 331 | ||
332 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, | 332 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, |
@@ -398,8 +398,7 @@ disconnect_all: | |||
398 | nfc_hci_disconnect_all_gates(hdev); | 398 | nfc_hci_disconnect_all_gates(hdev); |
399 | 399 | ||
400 | exit: | 400 | exit: |
401 | if (skb) | 401 | kfree_skb(skb); |
402 | kfree_skb(skb); | ||
403 | 402 | ||
404 | return r; | 403 | return r; |
405 | } | 404 | } |
@@ -470,29 +469,38 @@ static int hci_dev_up(struct nfc_dev *nfc_dev) | |||
470 | return r; | 469 | return r; |
471 | } | 470 | } |
472 | 471 | ||
472 | r = nfc_llc_start(hdev->llc); | ||
473 | if (r < 0) | ||
474 | goto exit_close; | ||
475 | |||
473 | r = hci_dev_session_init(hdev); | 476 | r = hci_dev_session_init(hdev); |
474 | if (r < 0) | 477 | if (r < 0) |
475 | goto exit; | 478 | goto exit_llc; |
476 | 479 | ||
477 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | 480 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, |
478 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | 481 | NFC_HCI_EVT_END_OPERATION, NULL, 0); |
479 | if (r < 0) | 482 | if (r < 0) |
480 | goto exit; | 483 | goto exit_llc; |
481 | 484 | ||
482 | if (hdev->ops->hci_ready) { | 485 | if (hdev->ops->hci_ready) { |
483 | r = hdev->ops->hci_ready(hdev); | 486 | r = hdev->ops->hci_ready(hdev); |
484 | if (r < 0) | 487 | if (r < 0) |
485 | goto exit; | 488 | goto exit_llc; |
486 | } | 489 | } |
487 | 490 | ||
488 | r = hci_dev_version(hdev); | 491 | r = hci_dev_version(hdev); |
489 | if (r < 0) | 492 | if (r < 0) |
490 | goto exit; | 493 | goto exit_llc; |
494 | |||
495 | return 0; | ||
496 | |||
497 | exit_llc: | ||
498 | nfc_llc_stop(hdev->llc); | ||
499 | |||
500 | exit_close: | ||
501 | if (hdev->ops->close) | ||
502 | hdev->ops->close(hdev); | ||
491 | 503 | ||
492 | exit: | ||
493 | if (r < 0) | ||
494 | if (hdev->ops->close) | ||
495 | hdev->ops->close(hdev); | ||
496 | return r; | 504 | return r; |
497 | } | 505 | } |
498 | 506 | ||
@@ -500,6 +508,8 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) | |||
500 | { | 508 | { |
501 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 509 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
502 | 510 | ||
511 | nfc_llc_stop(hdev->llc); | ||
512 | |||
503 | if (hdev->ops->close) | 513 | if (hdev->ops->close) |
504 | hdev->ops->close(hdev); | 514 | hdev->ops->close(hdev); |
505 | 515 | ||
@@ -539,13 +549,37 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev, | |||
539 | { | 549 | { |
540 | } | 550 | } |
541 | 551 | ||
552 | #define HCI_CB_TYPE_TRANSCEIVE 1 | ||
553 | |||
554 | static void hci_transceive_cb(void *context, struct sk_buff *skb, int err) | ||
555 | { | ||
556 | struct nfc_hci_dev *hdev = context; | ||
557 | |||
558 | switch (hdev->async_cb_type) { | ||
559 | case HCI_CB_TYPE_TRANSCEIVE: | ||
560 | /* | ||
561 | * TODO: Check RF Error indicator to make sure data is valid. | ||
562 | * It seems that HCI cmd can complete without error, but data | ||
563 | * can be invalid if an RF error occured? Ignore for now. | ||
564 | */ | ||
565 | if (err == 0) | ||
566 | skb_trim(skb, skb->len - 1); /* RF Err ind */ | ||
567 | |||
568 | hdev->async_cb(hdev->async_cb_context, skb, err); | ||
569 | break; | ||
570 | default: | ||
571 | if (err == 0) | ||
572 | kfree_skb(skb); | ||
573 | break; | ||
574 | } | ||
575 | } | ||
576 | |||
542 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 577 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
543 | struct sk_buff *skb, data_exchange_cb_t cb, | 578 | struct sk_buff *skb, data_exchange_cb_t cb, |
544 | void *cb_context) | 579 | void *cb_context) |
545 | { | 580 | { |
546 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 581 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
547 | int r; | 582 | int r; |
548 | struct sk_buff *res_skb = NULL; | ||
549 | 583 | ||
550 | pr_debug("target_idx=%d\n", target->idx); | 584 | pr_debug("target_idx=%d\n", target->idx); |
551 | 585 | ||
@@ -553,40 +587,37 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
553 | case NFC_HCI_RF_READER_A_GATE: | 587 | case NFC_HCI_RF_READER_A_GATE: |
554 | case NFC_HCI_RF_READER_B_GATE: | 588 | case NFC_HCI_RF_READER_B_GATE: |
555 | if (hdev->ops->data_exchange) { | 589 | if (hdev->ops->data_exchange) { |
556 | r = hdev->ops->data_exchange(hdev, target, skb, | 590 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
557 | &res_skb); | 591 | cb_context); |
558 | if (r <= 0) /* handled */ | 592 | if (r <= 0) /* handled */ |
559 | break; | 593 | break; |
560 | } | 594 | } |
561 | 595 | ||
562 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ | 596 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ |
563 | r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 597 | |
564 | NFC_HCI_WR_XCHG_DATA, | 598 | hdev->async_cb_type = HCI_CB_TYPE_TRANSCEIVE; |
565 | skb->data, skb->len, &res_skb); | 599 | hdev->async_cb = cb; |
566 | /* | 600 | hdev->async_cb_context = cb_context; |
567 | * TODO: Check RF Error indicator to make sure data is valid. | 601 | |
568 | * It seems that HCI cmd can complete without error, but data | 602 | r = nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
569 | * can be invalid if an RF error occured? Ignore for now. | 603 | NFC_HCI_WR_XCHG_DATA, skb->data, |
570 | */ | 604 | skb->len, hci_transceive_cb, hdev); |
571 | if (r == 0) | ||
572 | skb_trim(res_skb, res_skb->len - 1); /* RF Err ind */ | ||
573 | break; | 605 | break; |
574 | default: | 606 | default: |
575 | if (hdev->ops->data_exchange) { | 607 | if (hdev->ops->data_exchange) { |
576 | r = hdev->ops->data_exchange(hdev, target, skb, | 608 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
577 | &res_skb); | 609 | cb_context); |
578 | if (r == 1) | 610 | if (r == 1) |
579 | r = -ENOTSUPP; | 611 | r = -ENOTSUPP; |
580 | } | 612 | } |
581 | else | 613 | else |
582 | r = -ENOTSUPP; | 614 | r = -ENOTSUPP; |
615 | break; | ||
583 | } | 616 | } |
584 | 617 | ||
585 | kfree_skb(skb); | 618 | kfree_skb(skb); |
586 | 619 | ||
587 | cb(cb_context, res_skb, r); | 620 | return r; |
588 | |||
589 | return 0; | ||
590 | } | 621 | } |
591 | 622 | ||
592 | static int hci_check_presence(struct nfc_dev *nfc_dev, | 623 | static int hci_check_presence(struct nfc_dev *nfc_dev, |
@@ -600,6 +631,93 @@ static int hci_check_presence(struct nfc_dev *nfc_dev, | |||
600 | return 0; | 631 | return 0; |
601 | } | 632 | } |
602 | 633 | ||
634 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
635 | { | ||
636 | mutex_lock(&hdev->msg_tx_mutex); | ||
637 | |||
638 | if (hdev->cmd_pending_msg == NULL) { | ||
639 | nfc_driver_failure(hdev->ndev, err); | ||
640 | goto exit; | ||
641 | } | ||
642 | |||
643 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
644 | |||
645 | exit: | ||
646 | mutex_unlock(&hdev->msg_tx_mutex); | ||
647 | } | ||
648 | |||
649 | static void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err) | ||
650 | { | ||
651 | nfc_hci_failure(hdev, err); | ||
652 | } | ||
653 | |||
654 | static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
655 | { | ||
656 | struct hcp_packet *packet; | ||
657 | u8 type; | ||
658 | u8 instruction; | ||
659 | struct sk_buff *hcp_skb; | ||
660 | u8 pipe; | ||
661 | struct sk_buff *frag_skb; | ||
662 | int msg_len; | ||
663 | |||
664 | packet = (struct hcp_packet *)skb->data; | ||
665 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | ||
666 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | /* it's the last fragment. Does it need re-aggregation? */ | ||
671 | if (skb_queue_len(&hdev->rx_hcp_frags)) { | ||
672 | pipe = packet->header & NFC_HCI_FRAGMENT; | ||
673 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
674 | |||
675 | msg_len = 0; | ||
676 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
677 | msg_len += (frag_skb->len - | ||
678 | NFC_HCI_HCP_PACKET_HEADER_LEN); | ||
679 | } | ||
680 | |||
681 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
682 | msg_len, GFP_KERNEL); | ||
683 | if (hcp_skb == NULL) { | ||
684 | nfc_hci_failure(hdev, -ENOMEM); | ||
685 | return; | ||
686 | } | ||
687 | |||
688 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | ||
689 | |||
690 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
691 | msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; | ||
692 | memcpy(skb_put(hcp_skb, msg_len), | ||
693 | frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, | ||
694 | msg_len); | ||
695 | } | ||
696 | |||
697 | skb_queue_purge(&hdev->rx_hcp_frags); | ||
698 | } else { | ||
699 | packet->header &= NFC_HCI_FRAGMENT; | ||
700 | hcp_skb = skb; | ||
701 | } | ||
702 | |||
703 | /* if this is a response, dispatch immediately to | ||
704 | * unblock waiting cmd context. Otherwise, enqueue to dispatch | ||
705 | * in separate context where handler can also execute command. | ||
706 | */ | ||
707 | packet = (struct hcp_packet *)hcp_skb->data; | ||
708 | type = HCP_MSG_GET_TYPE(packet->message.header); | ||
709 | if (type == NFC_HCI_HCP_RESPONSE) { | ||
710 | pipe = packet->header; | ||
711 | instruction = HCP_MSG_GET_CMD(packet->message.header); | ||
712 | skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
713 | NFC_HCI_HCP_MESSAGE_HEADER_LEN); | ||
714 | nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); | ||
715 | } else { | ||
716 | skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); | ||
717 | queue_work(system_nrt_wq, &hdev->msg_rx_work); | ||
718 | } | ||
719 | } | ||
720 | |||
603 | static struct nfc_ops hci_nfc_ops = { | 721 | static struct nfc_ops hci_nfc_ops = { |
604 | .dev_up = hci_dev_up, | 722 | .dev_up = hci_dev_up, |
605 | .dev_down = hci_dev_down, | 723 | .dev_down = hci_dev_down, |
@@ -614,6 +732,7 @@ static struct nfc_ops hci_nfc_ops = { | |||
614 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | 732 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, |
615 | struct nfc_hci_init_data *init_data, | 733 | struct nfc_hci_init_data *init_data, |
616 | u32 protocols, | 734 | u32 protocols, |
735 | const char *llc_name, | ||
617 | int tx_headroom, | 736 | int tx_headroom, |
618 | int tx_tailroom, | 737 | int tx_tailroom, |
619 | int max_link_payload) | 738 | int max_link_payload) |
@@ -630,10 +749,19 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | |||
630 | if (hdev == NULL) | 749 | if (hdev == NULL) |
631 | return NULL; | 750 | return NULL; |
632 | 751 | ||
752 | hdev->llc = nfc_llc_allocate(llc_name, hdev, ops->xmit, | ||
753 | nfc_hci_recv_from_llc, tx_headroom, | ||
754 | tx_tailroom, nfc_hci_llc_failure); | ||
755 | if (hdev->llc == NULL) { | ||
756 | kfree(hdev); | ||
757 | return NULL; | ||
758 | } | ||
759 | |||
633 | hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, | 760 | hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, |
634 | tx_headroom + HCI_CMDS_HEADROOM, | 761 | tx_headroom + HCI_CMDS_HEADROOM, |
635 | tx_tailroom); | 762 | tx_tailroom); |
636 | if (!hdev->ndev) { | 763 | if (!hdev->ndev) { |
764 | nfc_llc_free(hdev->llc); | ||
637 | kfree(hdev); | 765 | kfree(hdev); |
638 | return NULL; | 766 | return NULL; |
639 | } | 767 | } |
@@ -653,29 +781,18 @@ EXPORT_SYMBOL(nfc_hci_allocate_device); | |||
653 | void nfc_hci_free_device(struct nfc_hci_dev *hdev) | 781 | void nfc_hci_free_device(struct nfc_hci_dev *hdev) |
654 | { | 782 | { |
655 | nfc_free_device(hdev->ndev); | 783 | nfc_free_device(hdev->ndev); |
784 | nfc_llc_free(hdev->llc); | ||
656 | kfree(hdev); | 785 | kfree(hdev); |
657 | } | 786 | } |
658 | EXPORT_SYMBOL(nfc_hci_free_device); | 787 | EXPORT_SYMBOL(nfc_hci_free_device); |
659 | 788 | ||
660 | int nfc_hci_register_device(struct nfc_hci_dev *hdev) | 789 | int nfc_hci_register_device(struct nfc_hci_dev *hdev) |
661 | { | 790 | { |
662 | struct device *dev = &hdev->ndev->dev; | ||
663 | const char *devname = dev_name(dev); | ||
664 | char name[32]; | ||
665 | int r = 0; | ||
666 | |||
667 | mutex_init(&hdev->msg_tx_mutex); | 791 | mutex_init(&hdev->msg_tx_mutex); |
668 | 792 | ||
669 | INIT_LIST_HEAD(&hdev->msg_tx_queue); | 793 | INIT_LIST_HEAD(&hdev->msg_tx_queue); |
670 | 794 | ||
671 | INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); | 795 | INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); |
672 | snprintf(name, sizeof(name), "%s_hci_msg_tx_wq", devname); | ||
673 | hdev->msg_tx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
674 | WQ_MEM_RECLAIM, 1); | ||
675 | if (hdev->msg_tx_wq == NULL) { | ||
676 | r = -ENOMEM; | ||
677 | goto exit; | ||
678 | } | ||
679 | 796 | ||
680 | init_timer(&hdev->cmd_timer); | 797 | init_timer(&hdev->cmd_timer); |
681 | hdev->cmd_timer.data = (unsigned long)hdev; | 798 | hdev->cmd_timer.data = (unsigned long)hdev; |
@@ -684,27 +801,10 @@ int nfc_hci_register_device(struct nfc_hci_dev *hdev) | |||
684 | skb_queue_head_init(&hdev->rx_hcp_frags); | 801 | skb_queue_head_init(&hdev->rx_hcp_frags); |
685 | 802 | ||
686 | INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); | 803 | INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); |
687 | snprintf(name, sizeof(name), "%s_hci_msg_rx_wq", devname); | ||
688 | hdev->msg_rx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
689 | WQ_MEM_RECLAIM, 1); | ||
690 | if (hdev->msg_rx_wq == NULL) { | ||
691 | r = -ENOMEM; | ||
692 | goto exit; | ||
693 | } | ||
694 | 804 | ||
695 | skb_queue_head_init(&hdev->msg_rx_queue); | 805 | skb_queue_head_init(&hdev->msg_rx_queue); |
696 | 806 | ||
697 | r = nfc_register_device(hdev->ndev); | 807 | return nfc_register_device(hdev->ndev); |
698 | |||
699 | exit: | ||
700 | if (r < 0) { | ||
701 | if (hdev->msg_tx_wq) | ||
702 | destroy_workqueue(hdev->msg_tx_wq); | ||
703 | if (hdev->msg_rx_wq) | ||
704 | destroy_workqueue(hdev->msg_rx_wq); | ||
705 | } | ||
706 | |||
707 | return r; | ||
708 | } | 808 | } |
709 | EXPORT_SYMBOL(nfc_hci_register_device); | 809 | EXPORT_SYMBOL(nfc_hci_register_device); |
710 | 810 | ||
@@ -725,9 +825,8 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev) | |||
725 | 825 | ||
726 | nfc_unregister_device(hdev->ndev); | 826 | nfc_unregister_device(hdev->ndev); |
727 | 827 | ||
728 | destroy_workqueue(hdev->msg_tx_wq); | 828 | cancel_work_sync(&hdev->msg_tx_work); |
729 | 829 | cancel_work_sync(&hdev->msg_rx_work); | |
730 | destroy_workqueue(hdev->msg_rx_wq); | ||
731 | } | 830 | } |
732 | EXPORT_SYMBOL(nfc_hci_unregister_device); | 831 | EXPORT_SYMBOL(nfc_hci_unregister_device); |
733 | 832 | ||
@@ -743,93 +842,30 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) | |||
743 | } | 842 | } |
744 | EXPORT_SYMBOL(nfc_hci_get_clientdata); | 843 | EXPORT_SYMBOL(nfc_hci_get_clientdata); |
745 | 844 | ||
746 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
747 | { | ||
748 | mutex_lock(&hdev->msg_tx_mutex); | ||
749 | |||
750 | if (hdev->cmd_pending_msg == NULL) { | ||
751 | nfc_driver_failure(hdev->ndev, err); | ||
752 | goto exit; | ||
753 | } | ||
754 | |||
755 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
756 | |||
757 | exit: | ||
758 | mutex_unlock(&hdev->msg_tx_mutex); | ||
759 | } | ||
760 | |||
761 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) | 845 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) |
762 | { | 846 | { |
763 | nfc_hci_failure(hdev, err); | 847 | nfc_hci_failure(hdev, err); |
764 | } | 848 | } |
765 | EXPORT_SYMBOL(nfc_hci_driver_failure); | 849 | EXPORT_SYMBOL(nfc_hci_driver_failure); |
766 | 850 | ||
767 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | 851 | void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
768 | { | 852 | { |
769 | struct hcp_packet *packet; | 853 | nfc_llc_rcv_from_drv(hdev->llc, skb); |
770 | u8 type; | 854 | } |
771 | u8 instruction; | 855 | EXPORT_SYMBOL(nfc_hci_recv_frame); |
772 | struct sk_buff *hcp_skb; | ||
773 | u8 pipe; | ||
774 | struct sk_buff *frag_skb; | ||
775 | int msg_len; | ||
776 | |||
777 | packet = (struct hcp_packet *)skb->data; | ||
778 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | ||
779 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | /* it's the last fragment. Does it need re-aggregation? */ | ||
784 | if (skb_queue_len(&hdev->rx_hcp_frags)) { | ||
785 | pipe = packet->header & NFC_HCI_FRAGMENT; | ||
786 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
787 | |||
788 | msg_len = 0; | ||
789 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
790 | msg_len += (frag_skb->len - | ||
791 | NFC_HCI_HCP_PACKET_HEADER_LEN); | ||
792 | } | ||
793 | |||
794 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
795 | msg_len, GFP_KERNEL); | ||
796 | if (hcp_skb == NULL) { | ||
797 | nfc_hci_failure(hdev, -ENOMEM); | ||
798 | return; | ||
799 | } | ||
800 | |||
801 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | ||
802 | |||
803 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
804 | msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; | ||
805 | memcpy(skb_put(hcp_skb, msg_len), | ||
806 | frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, | ||
807 | msg_len); | ||
808 | } | ||
809 | 856 | ||
810 | skb_queue_purge(&hdev->rx_hcp_frags); | 857 | static int __init nfc_hci_init(void) |
811 | } else { | 858 | { |
812 | packet->header &= NFC_HCI_FRAGMENT; | 859 | return nfc_llc_init(); |
813 | hcp_skb = skb; | 860 | } |
814 | } | ||
815 | 861 | ||
816 | /* if this is a response, dispatch immediately to | 862 | static void __exit nfc_hci_exit(void) |
817 | * unblock waiting cmd context. Otherwise, enqueue to dispatch | 863 | { |
818 | * in separate context where handler can also execute command. | 864 | nfc_llc_exit(); |
819 | */ | ||
820 | packet = (struct hcp_packet *)hcp_skb->data; | ||
821 | type = HCP_MSG_GET_TYPE(packet->message.header); | ||
822 | if (type == NFC_HCI_HCP_RESPONSE) { | ||
823 | pipe = packet->header; | ||
824 | instruction = HCP_MSG_GET_CMD(packet->message.header); | ||
825 | skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
826 | NFC_HCI_HCP_MESSAGE_HEADER_LEN); | ||
827 | nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); | ||
828 | } else { | ||
829 | skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); | ||
830 | queue_work(hdev->msg_rx_wq, &hdev->msg_rx_work); | ||
831 | } | ||
832 | } | 865 | } |
833 | EXPORT_SYMBOL(nfc_hci_recv_frame); | 866 | |
867 | subsys_initcall(nfc_hci_init); | ||
868 | module_exit(nfc_hci_exit); | ||
834 | 869 | ||
835 | MODULE_LICENSE("GPL"); | 870 | MODULE_LICENSE("GPL"); |
871 | MODULE_DESCRIPTION("NFC HCI Core"); | ||
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index fa9a21e92239..b274d12c18ac 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h | |||
@@ -20,6 +20,8 @@ | |||
20 | #ifndef __LOCAL_HCI_H | 20 | #ifndef __LOCAL_HCI_H |
21 | #define __LOCAL_HCI_H | 21 | #define __LOCAL_HCI_H |
22 | 22 | ||
23 | #include <net/nfc/hci.h> | ||
24 | |||
23 | struct gate_pipe_map { | 25 | struct gate_pipe_map { |
24 | u8 gate; | 26 | u8 gate; |
25 | u8 pipe; | 27 | u8 pipe; |
@@ -35,15 +37,6 @@ struct hcp_packet { | |||
35 | struct hcp_message message; | 37 | struct hcp_message message; |
36 | } __packed; | 38 | } __packed; |
37 | 39 | ||
38 | /* | ||
39 | * HCI command execution completion callback. | ||
40 | * result will be a standard linux error (may be converted from HCI response) | ||
41 | * skb contains the response data and must be disposed, or may be NULL if | ||
42 | * an error occured | ||
43 | */ | ||
44 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, | ||
45 | struct sk_buff *skb, void *cb_data); | ||
46 | |||
47 | struct hcp_exec_waiter { | 40 | struct hcp_exec_waiter { |
48 | wait_queue_head_t *wq; | 41 | wait_queue_head_t *wq; |
49 | bool exec_complete; | 42 | bool exec_complete; |
@@ -55,7 +48,7 @@ struct hci_msg { | |||
55 | struct list_head msg_l; | 48 | struct list_head msg_l; |
56 | struct sk_buff_head msg_frags; | 49 | struct sk_buff_head msg_frags; |
57 | bool wait_response; | 50 | bool wait_response; |
58 | hci_cmd_cb_t cb; | 51 | data_exchange_cb_t cb; |
59 | void *cb_context; | 52 | void *cb_context; |
60 | unsigned long completion_delay; | 53 | unsigned long completion_delay; |
61 | }; | 54 | }; |
@@ -83,7 +76,7 @@ struct hci_create_pipe_resp { | |||
83 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | 76 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, |
84 | u8 type, u8 instruction, | 77 | u8 type, u8 instruction, |
85 | const u8 *payload, size_t payload_len, | 78 | const u8 *payload, size_t payload_len, |
86 | hci_cmd_cb_t cb, void *cb_data, | 79 | data_exchange_cb_t cb, void *cb_context, |
87 | unsigned long completion_delay); | 80 | unsigned long completion_delay); |
88 | 81 | ||
89 | u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe); | 82 | u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe); |
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index f4dad1a89740..208eedd07ee3 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c | |||
@@ -35,7 +35,7 @@ | |||
35 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | 35 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, |
36 | u8 type, u8 instruction, | 36 | u8 type, u8 instruction, |
37 | const u8 *payload, size_t payload_len, | 37 | const u8 *payload, size_t payload_len, |
38 | hci_cmd_cb_t cb, void *cb_data, | 38 | data_exchange_cb_t cb, void *cb_context, |
39 | unsigned long completion_delay) | 39 | unsigned long completion_delay) |
40 | { | 40 | { |
41 | struct nfc_dev *ndev = hdev->ndev; | 41 | struct nfc_dev *ndev = hdev->ndev; |
@@ -52,7 +52,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | |||
52 | skb_queue_head_init(&cmd->msg_frags); | 52 | skb_queue_head_init(&cmd->msg_frags); |
53 | cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; | 53 | cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; |
54 | cmd->cb = cb; | 54 | cmd->cb = cb; |
55 | cmd->cb_context = cb_data; | 55 | cmd->cb_context = cb_context; |
56 | cmd->completion_delay = completion_delay; | 56 | cmd->completion_delay = completion_delay; |
57 | 57 | ||
58 | hci_len = payload_len + 1; | 58 | hci_len = payload_len + 1; |
@@ -108,7 +108,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | |||
108 | list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); | 108 | list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); |
109 | mutex_unlock(&hdev->msg_tx_mutex); | 109 | mutex_unlock(&hdev->msg_tx_mutex); |
110 | 110 | ||
111 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 111 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
112 | 112 | ||
113 | return 0; | 113 | return 0; |
114 | 114 | ||
diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c new file mode 100644 index 000000000000..ae1205ded87f --- /dev/null +++ b/net/nfc/hci/llc.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <net/nfc/llc.h> | ||
22 | |||
23 | #include "llc.h" | ||
24 | |||
25 | static struct list_head llc_engines; | ||
26 | |||
27 | int nfc_llc_init(void) | ||
28 | { | ||
29 | int r; | ||
30 | |||
31 | INIT_LIST_HEAD(&llc_engines); | ||
32 | |||
33 | r = nfc_llc_nop_register(); | ||
34 | if (r) | ||
35 | goto exit; | ||
36 | |||
37 | r = nfc_llc_shdlc_register(); | ||
38 | if (r) | ||
39 | goto exit; | ||
40 | |||
41 | return 0; | ||
42 | |||
43 | exit: | ||
44 | nfc_llc_exit(); | ||
45 | return r; | ||
46 | } | ||
47 | |||
48 | void nfc_llc_exit(void) | ||
49 | { | ||
50 | struct nfc_llc_engine *llc_engine, *n; | ||
51 | |||
52 | list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) { | ||
53 | list_del(&llc_engine->entry); | ||
54 | kfree(llc_engine->name); | ||
55 | kfree(llc_engine); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | int nfc_llc_register(const char *name, struct nfc_llc_ops *ops) | ||
60 | { | ||
61 | struct nfc_llc_engine *llc_engine; | ||
62 | |||
63 | llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL); | ||
64 | if (llc_engine == NULL) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | llc_engine->name = kstrdup(name, GFP_KERNEL); | ||
68 | if (llc_engine->name == NULL) { | ||
69 | kfree(llc_engine); | ||
70 | return -ENOMEM; | ||
71 | } | ||
72 | llc_engine->ops = ops; | ||
73 | |||
74 | INIT_LIST_HEAD(&llc_engine->entry); | ||
75 | list_add_tail (&llc_engine->entry, &llc_engines); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name) | ||
81 | { | ||
82 | struct nfc_llc_engine *llc_engine; | ||
83 | |||
84 | list_for_each_entry(llc_engine, &llc_engines, entry) { | ||
85 | if (strcmp(llc_engine->name, name) == 0) | ||
86 | return llc_engine; | ||
87 | } | ||
88 | |||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | void nfc_llc_unregister(const char *name) | ||
93 | { | ||
94 | struct nfc_llc_engine *llc_engine; | ||
95 | |||
96 | llc_engine = nfc_llc_name_to_engine(name); | ||
97 | if (llc_engine == NULL) | ||
98 | return; | ||
99 | |||
100 | list_del(&llc_engine->entry); | ||
101 | kfree(llc_engine->name); | ||
102 | kfree(llc_engine); | ||
103 | } | ||
104 | |||
105 | struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev, | ||
106 | xmit_to_drv_t xmit_to_drv, | ||
107 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
108 | int tx_tailroom, llc_failure_t llc_failure) | ||
109 | { | ||
110 | struct nfc_llc_engine *llc_engine; | ||
111 | struct nfc_llc *llc; | ||
112 | |||
113 | llc_engine = nfc_llc_name_to_engine(name); | ||
114 | if (llc_engine == NULL) | ||
115 | return NULL; | ||
116 | |||
117 | llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL); | ||
118 | if (llc == NULL) | ||
119 | return NULL; | ||
120 | |||
121 | llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci, | ||
122 | tx_headroom, tx_tailroom, | ||
123 | &llc->rx_headroom, &llc->rx_tailroom, | ||
124 | llc_failure); | ||
125 | if (llc->data == NULL) { | ||
126 | kfree(llc); | ||
127 | return NULL; | ||
128 | } | ||
129 | llc->ops = llc_engine->ops; | ||
130 | |||
131 | return llc; | ||
132 | } | ||
133 | |||
134 | void nfc_llc_free(struct nfc_llc *llc) | ||
135 | { | ||
136 | llc->ops->deinit(llc); | ||
137 | kfree(llc); | ||
138 | } | ||
139 | |||
140 | inline void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom, | ||
141 | int *rx_tailroom) | ||
142 | { | ||
143 | *rx_headroom = llc->rx_headroom; | ||
144 | *rx_tailroom = llc->rx_tailroom; | ||
145 | } | ||
146 | |||
147 | inline int nfc_llc_start(struct nfc_llc *llc) | ||
148 | { | ||
149 | return llc->ops->start(llc); | ||
150 | } | ||
151 | |||
152 | inline int nfc_llc_stop(struct nfc_llc *llc) | ||
153 | { | ||
154 | return llc->ops->stop(llc); | ||
155 | } | ||
156 | |||
157 | inline void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) | ||
158 | { | ||
159 | llc->ops->rcv_from_drv(llc, skb); | ||
160 | } | ||
161 | |||
162 | inline int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) | ||
163 | { | ||
164 | return llc->ops->xmit_from_hci(llc, skb); | ||
165 | } | ||
166 | |||
167 | inline void *nfc_llc_get_data(struct nfc_llc *llc) | ||
168 | { | ||
169 | return llc->data; | ||
170 | } | ||
diff --git a/net/nfc/hci/llc.h b/net/nfc/hci/llc.h new file mode 100644 index 000000000000..7be0b7f3ceb6 --- /dev/null +++ b/net/nfc/hci/llc.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __LOCAL_LLC_H_ | ||
22 | #define __LOCAL_LLC_H_ | ||
23 | |||
24 | #include <net/nfc/hci.h> | ||
25 | #include <net/nfc/llc.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | struct nfc_llc_ops { | ||
29 | void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | ||
30 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
31 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
32 | llc_failure_t llc_failure); | ||
33 | void (*deinit) (struct nfc_llc *llc); | ||
34 | int (*start) (struct nfc_llc *llc); | ||
35 | int (*stop) (struct nfc_llc *llc); | ||
36 | void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb); | ||
37 | int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb); | ||
38 | }; | ||
39 | |||
40 | struct nfc_llc_engine { | ||
41 | const char *name; | ||
42 | struct nfc_llc_ops *ops; | ||
43 | struct list_head entry; | ||
44 | }; | ||
45 | |||
46 | struct nfc_llc { | ||
47 | void *data; | ||
48 | struct nfc_llc_ops *ops; | ||
49 | int rx_headroom; | ||
50 | int rx_tailroom; | ||
51 | }; | ||
52 | |||
53 | void *nfc_llc_get_data(struct nfc_llc *llc); | ||
54 | |||
55 | int nfc_llc_register(const char *name, struct nfc_llc_ops *ops); | ||
56 | void nfc_llc_unregister(const char *name); | ||
57 | |||
58 | int nfc_llc_nop_register(void); | ||
59 | |||
60 | #if defined(CONFIG_NFC_SHDLC) | ||
61 | int nfc_llc_shdlc_register(void); | ||
62 | #else | ||
63 | static inline int nfc_llc_shdlc_register(void) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | #endif | ||
68 | |||
69 | #endif /* __LOCAL_LLC_H_ */ | ||
diff --git a/net/nfc/hci/llc_nop.c b/net/nfc/hci/llc_nop.c new file mode 100644 index 000000000000..87b10291b40f --- /dev/null +++ b/net/nfc/hci/llc_nop.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * nop (passthrough) Link Layer Control | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | #include "llc.h" | ||
24 | |||
25 | struct llc_nop { | ||
26 | struct nfc_hci_dev *hdev; | ||
27 | xmit_to_drv_t xmit_to_drv; | ||
28 | rcv_to_hci_t rcv_to_hci; | ||
29 | int tx_headroom; | ||
30 | int tx_tailroom; | ||
31 | llc_failure_t llc_failure; | ||
32 | }; | ||
33 | |||
34 | static void *llc_nop_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | ||
35 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
36 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
37 | llc_failure_t llc_failure) | ||
38 | { | ||
39 | struct llc_nop *llc_nop; | ||
40 | |||
41 | *rx_headroom = 0; | ||
42 | *rx_tailroom = 0; | ||
43 | |||
44 | llc_nop = kzalloc(sizeof(struct llc_nop), GFP_KERNEL); | ||
45 | if (llc_nop == NULL) | ||
46 | return NULL; | ||
47 | |||
48 | llc_nop->hdev = hdev; | ||
49 | llc_nop->xmit_to_drv = xmit_to_drv; | ||
50 | llc_nop->rcv_to_hci = rcv_to_hci; | ||
51 | llc_nop->tx_headroom = tx_headroom; | ||
52 | llc_nop->tx_tailroom = tx_tailroom; | ||
53 | llc_nop->llc_failure = llc_failure; | ||
54 | |||
55 | return llc_nop; | ||
56 | } | ||
57 | |||
58 | static void llc_nop_deinit(struct nfc_llc *llc) | ||
59 | { | ||
60 | kfree(nfc_llc_get_data(llc)); | ||
61 | } | ||
62 | |||
63 | static int llc_nop_start(struct nfc_llc *llc) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int llc_nop_stop(struct nfc_llc *llc) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void llc_nop_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) | ||
74 | { | ||
75 | struct llc_nop *llc_nop = nfc_llc_get_data(llc); | ||
76 | |||
77 | llc_nop->rcv_to_hci(llc_nop->hdev, skb); | ||
78 | } | ||
79 | |||
80 | static int llc_nop_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) | ||
81 | { | ||
82 | struct llc_nop *llc_nop = nfc_llc_get_data(llc); | ||
83 | |||
84 | return llc_nop->xmit_to_drv(llc_nop->hdev, skb); | ||
85 | } | ||
86 | |||
87 | static struct nfc_llc_ops llc_nop_ops = { | ||
88 | .init = llc_nop_init, | ||
89 | .deinit = llc_nop_deinit, | ||
90 | .start = llc_nop_start, | ||
91 | .stop = llc_nop_stop, | ||
92 | .rcv_from_drv = llc_nop_rcv_from_drv, | ||
93 | .xmit_from_hci = llc_nop_xmit_from_hci, | ||
94 | }; | ||
95 | |||
96 | int nfc_llc_nop_register(void) | ||
97 | { | ||
98 | return nfc_llc_register(LLC_NOP_NAME, &llc_nop_ops); | ||
99 | } | ||
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/llc_shdlc.c index 6f840c18c892..8f69d791dcb3 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/llc_shdlc.c | |||
@@ -1,10 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * shdlc Link Layer Control | ||
3 | * | ||
2 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | 4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. |
3 | * | 5 | * |
4 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify it |
5 | * it under the terms of the GNU General Public License as published by | 7 | * under the terms and conditions of the GNU General Public License, |
6 | * the Free Software Foundation; either version 2 of the License, or | 8 | * version 2, as published by the Free Software Foundation. |
7 | * (at your option) any later version. | ||
8 | * | 9 | * |
9 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
@@ -19,18 +20,65 @@ | |||
19 | 20 | ||
20 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ | 21 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ |
21 | 22 | ||
23 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
23 | #include <linux/export.h> | ||
24 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
25 | #include <linux/crc-ccitt.h> | ||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | 28 | ||
29 | #include <net/nfc/hci.h> | 29 | #include "llc.h" |
30 | #include <net/nfc/shdlc.h> | 30 | |
31 | enum shdlc_state { | ||
32 | SHDLC_DISCONNECTED = 0, | ||
33 | SHDLC_CONNECTING = 1, | ||
34 | SHDLC_NEGOTIATING = 2, | ||
35 | SHDLC_HALF_CONNECTED = 3, | ||
36 | SHDLC_CONNECTED = 4 | ||
37 | }; | ||
38 | |||
39 | struct llc_shdlc { | ||
40 | struct nfc_hci_dev *hdev; | ||
41 | xmit_to_drv_t xmit_to_drv; | ||
42 | rcv_to_hci_t rcv_to_hci; | ||
43 | |||
44 | struct mutex state_mutex; | ||
45 | enum shdlc_state state; | ||
46 | int hard_fault; | ||
47 | |||
48 | wait_queue_head_t *connect_wq; | ||
49 | int connect_tries; | ||
50 | int connect_result; | ||
51 | struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ | ||
52 | |||
53 | u8 w; /* window size */ | ||
54 | bool srej_support; | ||
55 | |||
56 | struct timer_list t1_timer; /* send ack timeout */ | ||
57 | bool t1_active; | ||
58 | |||
59 | struct timer_list t2_timer; /* guard/retransmit timeout */ | ||
60 | bool t2_active; | ||
61 | |||
62 | int ns; /* next seq num for send */ | ||
63 | int nr; /* next expected seq num for receive */ | ||
64 | int dnr; /* oldest sent unacked seq num */ | ||
65 | |||
66 | struct sk_buff_head rcv_q; | ||
67 | |||
68 | struct sk_buff_head send_q; | ||
69 | bool rnr; /* other side is not ready to receive */ | ||
70 | |||
71 | struct sk_buff_head ack_pending_q; | ||
72 | |||
73 | struct work_struct sm_work; | ||
74 | |||
75 | int tx_headroom; | ||
76 | int tx_tailroom; | ||
77 | |||
78 | llc_failure_t llc_failure; | ||
79 | }; | ||
31 | 80 | ||
32 | #define SHDLC_LLC_HEAD_ROOM 2 | 81 | #define SHDLC_LLC_HEAD_ROOM 2 |
33 | #define SHDLC_LLC_TAIL_ROOM 2 | ||
34 | 82 | ||
35 | #define SHDLC_MAX_WINDOW 4 | 83 | #define SHDLC_MAX_WINDOW 4 |
36 | #define SHDLC_SREJ_SUPPORT false | 84 | #define SHDLC_SREJ_SUPPORT false |
@@ -71,7 +119,7 @@ do { \ | |||
71 | } while (0) | 119 | } while (0) |
72 | 120 | ||
73 | /* checks x < y <= z modulo 8 */ | 121 | /* checks x < y <= z modulo 8 */ |
74 | static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) | 122 | static bool llc_shdlc_x_lt_y_lteq_z(int x, int y, int z) |
75 | { | 123 | { |
76 | if (x < z) | 124 | if (x < z) |
77 | return ((x < y) && (y <= z)) ? true : false; | 125 | return ((x < y) && (y <= z)) ? true : false; |
@@ -80,7 +128,7 @@ static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) | |||
80 | } | 128 | } |
81 | 129 | ||
82 | /* checks x <= y < z modulo 8 */ | 130 | /* checks x <= y < z modulo 8 */ |
83 | static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) | 131 | static bool llc_shdlc_x_lteq_y_lt_z(int x, int y, int z) |
84 | { | 132 | { |
85 | if (x <= z) | 133 | if (x <= z) |
86 | return ((x <= y) && (y < z)) ? true : false; | 134 | return ((x <= y) && (y < z)) ? true : false; |
@@ -88,36 +136,21 @@ static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) | |||
88 | return ((y >= x) || (y < z)) ? true : false; | 136 | return ((y >= x) || (y < z)) ? true : false; |
89 | } | 137 | } |
90 | 138 | ||
91 | static struct sk_buff *nfc_shdlc_alloc_skb(struct nfc_shdlc *shdlc, | 139 | static struct sk_buff *llc_shdlc_alloc_skb(struct llc_shdlc *shdlc, |
92 | int payload_len) | 140 | int payload_len) |
93 | { | 141 | { |
94 | struct sk_buff *skb; | 142 | struct sk_buff *skb; |
95 | 143 | ||
96 | skb = alloc_skb(shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM + | 144 | skb = alloc_skb(shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM + |
97 | shdlc->client_tailroom + SHDLC_LLC_TAIL_ROOM + | 145 | shdlc->tx_tailroom + payload_len, GFP_KERNEL); |
98 | payload_len, GFP_KERNEL); | ||
99 | if (skb) | 146 | if (skb) |
100 | skb_reserve(skb, shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM); | 147 | skb_reserve(skb, shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM); |
101 | 148 | ||
102 | return skb; | 149 | return skb; |
103 | } | 150 | } |
104 | 151 | ||
105 | static void nfc_shdlc_add_len_crc(struct sk_buff *skb) | ||
106 | { | ||
107 | u16 crc; | ||
108 | int len; | ||
109 | |||
110 | len = skb->len + 2; | ||
111 | *skb_push(skb, 1) = len; | ||
112 | |||
113 | crc = crc_ccitt(0xffff, skb->data, skb->len); | ||
114 | crc = ~crc; | ||
115 | *skb_put(skb, 1) = crc & 0xff; | ||
116 | *skb_put(skb, 1) = crc >> 8; | ||
117 | } | ||
118 | |||
119 | /* immediately sends an S frame. */ | 152 | /* immediately sends an S frame. */ |
120 | static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | 153 | static int llc_shdlc_send_s_frame(struct llc_shdlc *shdlc, |
121 | enum sframe_type sframe_type, int nr) | 154 | enum sframe_type sframe_type, int nr) |
122 | { | 155 | { |
123 | int r; | 156 | int r; |
@@ -125,15 +158,13 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | |||
125 | 158 | ||
126 | pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); | 159 | pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); |
127 | 160 | ||
128 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 161 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
129 | if (skb == NULL) | 162 | if (skb == NULL) |
130 | return -ENOMEM; | 163 | return -ENOMEM; |
131 | 164 | ||
132 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; | 165 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; |
133 | 166 | ||
134 | nfc_shdlc_add_len_crc(skb); | 167 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
135 | |||
136 | r = shdlc->ops->xmit(shdlc, skb); | ||
137 | 168 | ||
138 | kfree_skb(skb); | 169 | kfree_skb(skb); |
139 | 170 | ||
@@ -141,7 +172,7 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | |||
141 | } | 172 | } |
142 | 173 | ||
143 | /* immediately sends an U frame. skb may contain optional payload */ | 174 | /* immediately sends an U frame. skb may contain optional payload */ |
144 | static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | 175 | static int llc_shdlc_send_u_frame(struct llc_shdlc *shdlc, |
145 | struct sk_buff *skb, | 176 | struct sk_buff *skb, |
146 | enum uframe_modifier uframe_modifier) | 177 | enum uframe_modifier uframe_modifier) |
147 | { | 178 | { |
@@ -151,9 +182,7 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | |||
151 | 182 | ||
152 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; | 183 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; |
153 | 184 | ||
154 | nfc_shdlc_add_len_crc(skb); | 185 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
155 | |||
156 | r = shdlc->ops->xmit(shdlc, skb); | ||
157 | 186 | ||
158 | kfree_skb(skb); | 187 | kfree_skb(skb); |
159 | 188 | ||
@@ -164,7 +193,7 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | |||
164 | * Free ack_pending frames until y_nr - 1, and reset t2 according to | 193 | * Free ack_pending frames until y_nr - 1, and reset t2 according to |
165 | * the remaining oldest ack_pending frame sent time | 194 | * the remaining oldest ack_pending frame sent time |
166 | */ | 195 | */ |
167 | static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) | 196 | static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr) |
168 | { | 197 | { |
169 | struct sk_buff *skb; | 198 | struct sk_buff *skb; |
170 | int dnr = shdlc->dnr; /* MUST initially be < y_nr */ | 199 | int dnr = shdlc->dnr; /* MUST initially be < y_nr */ |
@@ -204,7 +233,7 @@ static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) | |||
204 | * Receive validated frames from lower layer. skb contains HCI payload only. | 233 | * Receive validated frames from lower layer. skb contains HCI payload only. |
205 | * Handle according to algorithm at spec:10.8.2 | 234 | * Handle according to algorithm at spec:10.8.2 |
206 | */ | 235 | */ |
207 | static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, | 236 | static void llc_shdlc_rcv_i_frame(struct llc_shdlc *shdlc, |
208 | struct sk_buff *skb, int ns, int nr) | 237 | struct sk_buff *skb, int ns, int nr) |
209 | { | 238 | { |
210 | int x_ns = ns; | 239 | int x_ns = ns; |
@@ -216,66 +245,64 @@ static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, | |||
216 | goto exit; | 245 | goto exit; |
217 | 246 | ||
218 | if (x_ns != shdlc->nr) { | 247 | if (x_ns != shdlc->nr) { |
219 | nfc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); | 248 | llc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); |
220 | goto exit; | 249 | goto exit; |
221 | } | 250 | } |
222 | 251 | ||
223 | if (shdlc->t1_active == false) { | 252 | if (shdlc->t1_active == false) { |
224 | shdlc->t1_active = true; | 253 | shdlc->t1_active = true; |
225 | mod_timer(&shdlc->t1_timer, | 254 | mod_timer(&shdlc->t1_timer, jiffies + |
226 | msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); | 255 | msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); |
227 | pr_debug("(re)Start T1(send ack)\n"); | 256 | pr_debug("(re)Start T1(send ack)\n"); |
228 | } | 257 | } |
229 | 258 | ||
230 | if (skb->len) { | 259 | if (skb->len) { |
231 | nfc_hci_recv_frame(shdlc->hdev, skb); | 260 | shdlc->rcv_to_hci(shdlc->hdev, skb); |
232 | skb = NULL; | 261 | skb = NULL; |
233 | } | 262 | } |
234 | 263 | ||
235 | shdlc->nr = (shdlc->nr + 1) % 8; | 264 | shdlc->nr = (shdlc->nr + 1) % 8; |
236 | 265 | ||
237 | if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { | 266 | if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { |
238 | nfc_shdlc_reset_t2(shdlc, y_nr); | 267 | llc_shdlc_reset_t2(shdlc, y_nr); |
239 | 268 | ||
240 | shdlc->dnr = y_nr; | 269 | shdlc->dnr = y_nr; |
241 | } | 270 | } |
242 | 271 | ||
243 | exit: | 272 | exit: |
244 | if (skb) | 273 | kfree_skb(skb); |
245 | kfree_skb(skb); | ||
246 | } | 274 | } |
247 | 275 | ||
248 | static void nfc_shdlc_rcv_ack(struct nfc_shdlc *shdlc, int y_nr) | 276 | static void llc_shdlc_rcv_ack(struct llc_shdlc *shdlc, int y_nr) |
249 | { | 277 | { |
250 | pr_debug("remote acked up to frame %d excluded\n", y_nr); | 278 | pr_debug("remote acked up to frame %d excluded\n", y_nr); |
251 | 279 | ||
252 | if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { | 280 | if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { |
253 | nfc_shdlc_reset_t2(shdlc, y_nr); | 281 | llc_shdlc_reset_t2(shdlc, y_nr); |
254 | shdlc->dnr = y_nr; | 282 | shdlc->dnr = y_nr; |
255 | } | 283 | } |
256 | } | 284 | } |
257 | 285 | ||
258 | static void nfc_shdlc_requeue_ack_pending(struct nfc_shdlc *shdlc) | 286 | static void llc_shdlc_requeue_ack_pending(struct llc_shdlc *shdlc) |
259 | { | 287 | { |
260 | struct sk_buff *skb; | 288 | struct sk_buff *skb; |
261 | 289 | ||
262 | pr_debug("ns reset to %d\n", shdlc->dnr); | 290 | pr_debug("ns reset to %d\n", shdlc->dnr); |
263 | 291 | ||
264 | while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { | 292 | while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { |
265 | skb_pull(skb, 2); /* remove len+control */ | 293 | skb_pull(skb, 1); /* remove control field */ |
266 | skb_trim(skb, skb->len - 2); /* remove crc */ | ||
267 | skb_queue_head(&shdlc->send_q, skb); | 294 | skb_queue_head(&shdlc->send_q, skb); |
268 | } | 295 | } |
269 | shdlc->ns = shdlc->dnr; | 296 | shdlc->ns = shdlc->dnr; |
270 | } | 297 | } |
271 | 298 | ||
272 | static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) | 299 | static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr) |
273 | { | 300 | { |
274 | struct sk_buff *skb; | 301 | struct sk_buff *skb; |
275 | 302 | ||
276 | pr_debug("remote asks retransmition from frame %d\n", y_nr); | 303 | pr_debug("remote asks retransmition from frame %d\n", y_nr); |
277 | 304 | ||
278 | if (nfc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { | 305 | if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { |
279 | if (shdlc->t2_active) { | 306 | if (shdlc->t2_active) { |
280 | del_timer_sync(&shdlc->t2_timer); | 307 | del_timer_sync(&shdlc->t2_timer); |
281 | shdlc->t2_active = false; | 308 | shdlc->t2_active = false; |
@@ -289,12 +316,12 @@ static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) | |||
289 | } | 316 | } |
290 | } | 317 | } |
291 | 318 | ||
292 | nfc_shdlc_requeue_ack_pending(shdlc); | 319 | llc_shdlc_requeue_ack_pending(shdlc); |
293 | } | 320 | } |
294 | } | 321 | } |
295 | 322 | ||
296 | /* See spec RR:10.8.3 REJ:10.8.4 */ | 323 | /* See spec RR:10.8.3 REJ:10.8.4 */ |
297 | static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | 324 | static void llc_shdlc_rcv_s_frame(struct llc_shdlc *shdlc, |
298 | enum sframe_type s_frame_type, int nr) | 325 | enum sframe_type s_frame_type, int nr) |
299 | { | 326 | { |
300 | struct sk_buff *skb; | 327 | struct sk_buff *skb; |
@@ -304,21 +331,21 @@ static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | |||
304 | 331 | ||
305 | switch (s_frame_type) { | 332 | switch (s_frame_type) { |
306 | case S_FRAME_RR: | 333 | case S_FRAME_RR: |
307 | nfc_shdlc_rcv_ack(shdlc, nr); | 334 | llc_shdlc_rcv_ack(shdlc, nr); |
308 | if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ | 335 | if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ |
309 | shdlc->rnr = false; | 336 | shdlc->rnr = false; |
310 | if (shdlc->send_q.qlen == 0) { | 337 | if (shdlc->send_q.qlen == 0) { |
311 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 338 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
312 | if (skb) | 339 | if (skb) |
313 | skb_queue_tail(&shdlc->send_q, skb); | 340 | skb_queue_tail(&shdlc->send_q, skb); |
314 | } | 341 | } |
315 | } | 342 | } |
316 | break; | 343 | break; |
317 | case S_FRAME_REJ: | 344 | case S_FRAME_REJ: |
318 | nfc_shdlc_rcv_rej(shdlc, nr); | 345 | llc_shdlc_rcv_rej(shdlc, nr); |
319 | break; | 346 | break; |
320 | case S_FRAME_RNR: | 347 | case S_FRAME_RNR: |
321 | nfc_shdlc_rcv_ack(shdlc, nr); | 348 | llc_shdlc_rcv_ack(shdlc, nr); |
322 | shdlc->rnr = true; | 349 | shdlc->rnr = true; |
323 | break; | 350 | break; |
324 | default: | 351 | default: |
@@ -326,7 +353,7 @@ static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | |||
326 | } | 353 | } |
327 | } | 354 | } |
328 | 355 | ||
329 | static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | 356 | static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r) |
330 | { | 357 | { |
331 | pr_debug("result=%d\n", r); | 358 | pr_debug("result=%d\n", r); |
332 | 359 | ||
@@ -337,7 +364,7 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
337 | shdlc->nr = 0; | 364 | shdlc->nr = 0; |
338 | shdlc->dnr = 0; | 365 | shdlc->dnr = 0; |
339 | 366 | ||
340 | shdlc->state = SHDLC_CONNECTED; | 367 | shdlc->state = SHDLC_HALF_CONNECTED; |
341 | } else { | 368 | } else { |
342 | shdlc->state = SHDLC_DISCONNECTED; | 369 | shdlc->state = SHDLC_DISCONNECTED; |
343 | } | 370 | } |
@@ -347,36 +374,36 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
347 | wake_up(shdlc->connect_wq); | 374 | wake_up(shdlc->connect_wq); |
348 | } | 375 | } |
349 | 376 | ||
350 | static int nfc_shdlc_connect_initiate(struct nfc_shdlc *shdlc) | 377 | static int llc_shdlc_connect_initiate(struct llc_shdlc *shdlc) |
351 | { | 378 | { |
352 | struct sk_buff *skb; | 379 | struct sk_buff *skb; |
353 | 380 | ||
354 | pr_debug("\n"); | 381 | pr_debug("\n"); |
355 | 382 | ||
356 | skb = nfc_shdlc_alloc_skb(shdlc, 2); | 383 | skb = llc_shdlc_alloc_skb(shdlc, 2); |
357 | if (skb == NULL) | 384 | if (skb == NULL) |
358 | return -ENOMEM; | 385 | return -ENOMEM; |
359 | 386 | ||
360 | *skb_put(skb, 1) = SHDLC_MAX_WINDOW; | 387 | *skb_put(skb, 1) = SHDLC_MAX_WINDOW; |
361 | *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; | 388 | *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; |
362 | 389 | ||
363 | return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); | 390 | return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); |
364 | } | 391 | } |
365 | 392 | ||
366 | static int nfc_shdlc_connect_send_ua(struct nfc_shdlc *shdlc) | 393 | static int llc_shdlc_connect_send_ua(struct llc_shdlc *shdlc) |
367 | { | 394 | { |
368 | struct sk_buff *skb; | 395 | struct sk_buff *skb; |
369 | 396 | ||
370 | pr_debug("\n"); | 397 | pr_debug("\n"); |
371 | 398 | ||
372 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 399 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
373 | if (skb == NULL) | 400 | if (skb == NULL) |
374 | return -ENOMEM; | 401 | return -ENOMEM; |
375 | 402 | ||
376 | return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); | 403 | return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); |
377 | } | 404 | } |
378 | 405 | ||
379 | static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | 406 | static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc, |
380 | struct sk_buff *skb, | 407 | struct sk_buff *skb, |
381 | enum uframe_modifier u_frame_modifier) | 408 | enum uframe_modifier u_frame_modifier) |
382 | { | 409 | { |
@@ -388,8 +415,13 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
388 | 415 | ||
389 | switch (u_frame_modifier) { | 416 | switch (u_frame_modifier) { |
390 | case U_FRAME_RSET: | 417 | case U_FRAME_RSET: |
391 | if (shdlc->state == SHDLC_NEGOCIATING) { | 418 | switch (shdlc->state) { |
392 | /* we sent RSET, but chip wants to negociate */ | 419 | case SHDLC_NEGOTIATING: |
420 | case SHDLC_CONNECTING: | ||
421 | /* | ||
422 | * We sent RSET, but chip wants to negociate or we | ||
423 | * got RSET before we managed to send out our. | ||
424 | */ | ||
393 | if (skb->len > 0) | 425 | if (skb->len > 0) |
394 | w = skb->data[0]; | 426 | w = skb->data[0]; |
395 | 427 | ||
@@ -401,22 +433,34 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
401 | (SHDLC_SREJ_SUPPORT || (srej_support == false))) { | 433 | (SHDLC_SREJ_SUPPORT || (srej_support == false))) { |
402 | shdlc->w = w; | 434 | shdlc->w = w; |
403 | shdlc->srej_support = srej_support; | 435 | shdlc->srej_support = srej_support; |
404 | r = nfc_shdlc_connect_send_ua(shdlc); | 436 | r = llc_shdlc_connect_send_ua(shdlc); |
405 | nfc_shdlc_connect_complete(shdlc, r); | 437 | llc_shdlc_connect_complete(shdlc, r); |
406 | } | 438 | } |
407 | } else if (shdlc->state == SHDLC_CONNECTED) { | 439 | break; |
440 | case SHDLC_HALF_CONNECTED: | ||
441 | /* | ||
442 | * Chip resent RSET due to its timeout - Ignote it | ||
443 | * as we already sent UA. | ||
444 | */ | ||
445 | break; | ||
446 | case SHDLC_CONNECTED: | ||
408 | /* | 447 | /* |
409 | * Chip wants to reset link. This is unexpected and | 448 | * Chip wants to reset link. This is unexpected and |
410 | * unsupported. | 449 | * unsupported. |
411 | */ | 450 | */ |
412 | shdlc->hard_fault = -ECONNRESET; | 451 | shdlc->hard_fault = -ECONNRESET; |
452 | break; | ||
453 | default: | ||
454 | break; | ||
413 | } | 455 | } |
414 | break; | 456 | break; |
415 | case U_FRAME_UA: | 457 | case U_FRAME_UA: |
416 | if ((shdlc->state == SHDLC_CONNECTING && | 458 | if ((shdlc->state == SHDLC_CONNECTING && |
417 | shdlc->connect_tries > 0) || | 459 | shdlc->connect_tries > 0) || |
418 | (shdlc->state == SHDLC_NEGOCIATING)) | 460 | (shdlc->state == SHDLC_NEGOTIATING)) { |
419 | nfc_shdlc_connect_complete(shdlc, 0); | 461 | llc_shdlc_connect_complete(shdlc, 0); |
462 | shdlc->state = SHDLC_CONNECTED; | ||
463 | } | ||
420 | break; | 464 | break; |
421 | default: | 465 | default: |
422 | break; | 466 | break; |
@@ -425,7 +469,7 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
425 | kfree_skb(skb); | 469 | kfree_skb(skb); |
426 | } | 470 | } |
427 | 471 | ||
428 | static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | 472 | static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc) |
429 | { | 473 | { |
430 | struct sk_buff *skb; | 474 | struct sk_buff *skb; |
431 | u8 control; | 475 | u8 control; |
@@ -443,19 +487,25 @@ static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | |||
443 | switch (control & SHDLC_CONTROL_HEAD_MASK) { | 487 | switch (control & SHDLC_CONTROL_HEAD_MASK) { |
444 | case SHDLC_CONTROL_HEAD_I: | 488 | case SHDLC_CONTROL_HEAD_I: |
445 | case SHDLC_CONTROL_HEAD_I2: | 489 | case SHDLC_CONTROL_HEAD_I2: |
490 | if (shdlc->state == SHDLC_HALF_CONNECTED) | ||
491 | shdlc->state = SHDLC_CONNECTED; | ||
492 | |||
446 | ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; | 493 | ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; |
447 | nr = control & SHDLC_CONTROL_NR_MASK; | 494 | nr = control & SHDLC_CONTROL_NR_MASK; |
448 | nfc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); | 495 | llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); |
449 | break; | 496 | break; |
450 | case SHDLC_CONTROL_HEAD_S: | 497 | case SHDLC_CONTROL_HEAD_S: |
498 | if (shdlc->state == SHDLC_HALF_CONNECTED) | ||
499 | shdlc->state = SHDLC_CONNECTED; | ||
500 | |||
451 | s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; | 501 | s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; |
452 | nr = control & SHDLC_CONTROL_NR_MASK; | 502 | nr = control & SHDLC_CONTROL_NR_MASK; |
453 | nfc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); | 503 | llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); |
454 | kfree_skb(skb); | 504 | kfree_skb(skb); |
455 | break; | 505 | break; |
456 | case SHDLC_CONTROL_HEAD_U: | 506 | case SHDLC_CONTROL_HEAD_U: |
457 | u_frame_modifier = control & SHDLC_CONTROL_M_MASK; | 507 | u_frame_modifier = control & SHDLC_CONTROL_M_MASK; |
458 | nfc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); | 508 | llc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); |
459 | break; | 509 | break; |
460 | default: | 510 | default: |
461 | pr_err("UNKNOWN Control=%d\n", control); | 511 | pr_err("UNKNOWN Control=%d\n", control); |
@@ -465,7 +515,7 @@ static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | |||
465 | } | 515 | } |
466 | } | 516 | } |
467 | 517 | ||
468 | static int nfc_shdlc_w_used(int ns, int dnr) | 518 | static int llc_shdlc_w_used(int ns, int dnr) |
469 | { | 519 | { |
470 | int unack_count; | 520 | int unack_count; |
471 | 521 | ||
@@ -478,7 +528,7 @@ static int nfc_shdlc_w_used(int ns, int dnr) | |||
478 | } | 528 | } |
479 | 529 | ||
480 | /* Send frames according to algorithm at spec:10.8.1 */ | 530 | /* Send frames according to algorithm at spec:10.8.1 */ |
481 | static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | 531 | static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) |
482 | { | 532 | { |
483 | struct sk_buff *skb; | 533 | struct sk_buff *skb; |
484 | int r; | 534 | int r; |
@@ -489,7 +539,7 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
489 | ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", | 539 | ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", |
490 | shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, | 540 | shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, |
491 | shdlc->rnr == false ? "false" : "true", | 541 | shdlc->rnr == false ? "false" : "true", |
492 | shdlc->w - nfc_shdlc_w_used(shdlc->ns, shdlc->dnr), | 542 | shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr), |
493 | shdlc->ack_pending_q.qlen); | 543 | shdlc->ack_pending_q.qlen); |
494 | 544 | ||
495 | while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && | 545 | while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && |
@@ -508,11 +558,9 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
508 | 558 | ||
509 | pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, | 559 | pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, |
510 | shdlc->nr); | 560 | shdlc->nr); |
511 | /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ | 561 | SHDLC_DUMP_SKB("shdlc frame written", skb); |
512 | |||
513 | nfc_shdlc_add_len_crc(skb); | ||
514 | 562 | ||
515 | r = shdlc->ops->xmit(shdlc, skb); | 563 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
516 | if (r < 0) { | 564 | if (r < 0) { |
517 | shdlc->hard_fault = r; | 565 | shdlc->hard_fault = r; |
518 | break; | 566 | break; |
@@ -534,36 +582,36 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
534 | } | 582 | } |
535 | } | 583 | } |
536 | 584 | ||
537 | static void nfc_shdlc_connect_timeout(unsigned long data) | 585 | static void llc_shdlc_connect_timeout(unsigned long data) |
538 | { | 586 | { |
539 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 587 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
540 | 588 | ||
541 | pr_debug("\n"); | 589 | pr_debug("\n"); |
542 | 590 | ||
543 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 591 | queue_work(system_nrt_wq, &shdlc->sm_work); |
544 | } | 592 | } |
545 | 593 | ||
546 | static void nfc_shdlc_t1_timeout(unsigned long data) | 594 | static void llc_shdlc_t1_timeout(unsigned long data) |
547 | { | 595 | { |
548 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 596 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
549 | 597 | ||
550 | pr_debug("SoftIRQ: need to send ack\n"); | 598 | pr_debug("SoftIRQ: need to send ack\n"); |
551 | 599 | ||
552 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 600 | queue_work(system_nrt_wq, &shdlc->sm_work); |
553 | } | 601 | } |
554 | 602 | ||
555 | static void nfc_shdlc_t2_timeout(unsigned long data) | 603 | static void llc_shdlc_t2_timeout(unsigned long data) |
556 | { | 604 | { |
557 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 605 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
558 | 606 | ||
559 | pr_debug("SoftIRQ: need to retransmit\n"); | 607 | pr_debug("SoftIRQ: need to retransmit\n"); |
560 | 608 | ||
561 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 609 | queue_work(system_nrt_wq, &shdlc->sm_work); |
562 | } | 610 | } |
563 | 611 | ||
564 | static void nfc_shdlc_sm_work(struct work_struct *work) | 612 | static void llc_shdlc_sm_work(struct work_struct *work) |
565 | { | 613 | { |
566 | struct nfc_shdlc *shdlc = container_of(work, struct nfc_shdlc, sm_work); | 614 | struct llc_shdlc *shdlc = container_of(work, struct llc_shdlc, sm_work); |
567 | int r; | 615 | int r; |
568 | 616 | ||
569 | pr_debug("\n"); | 617 | pr_debug("\n"); |
@@ -578,46 +626,47 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
578 | break; | 626 | break; |
579 | case SHDLC_CONNECTING: | 627 | case SHDLC_CONNECTING: |
580 | if (shdlc->hard_fault) { | 628 | if (shdlc->hard_fault) { |
581 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | 629 | llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); |
582 | break; | 630 | break; |
583 | } | 631 | } |
584 | 632 | ||
585 | if (shdlc->connect_tries++ < 5) | 633 | if (shdlc->connect_tries++ < 5) |
586 | r = nfc_shdlc_connect_initiate(shdlc); | 634 | r = llc_shdlc_connect_initiate(shdlc); |
587 | else | 635 | else |
588 | r = -ETIME; | 636 | r = -ETIME; |
589 | if (r < 0) | 637 | if (r < 0) |
590 | nfc_shdlc_connect_complete(shdlc, r); | 638 | llc_shdlc_connect_complete(shdlc, r); |
591 | else { | 639 | else { |
592 | mod_timer(&shdlc->connect_timer, jiffies + | 640 | mod_timer(&shdlc->connect_timer, jiffies + |
593 | msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); | 641 | msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); |
594 | 642 | ||
595 | shdlc->state = SHDLC_NEGOCIATING; | 643 | shdlc->state = SHDLC_NEGOTIATING; |
596 | } | 644 | } |
597 | break; | 645 | break; |
598 | case SHDLC_NEGOCIATING: | 646 | case SHDLC_NEGOTIATING: |
599 | if (timer_pending(&shdlc->connect_timer) == 0) { | 647 | if (timer_pending(&shdlc->connect_timer) == 0) { |
600 | shdlc->state = SHDLC_CONNECTING; | 648 | shdlc->state = SHDLC_CONNECTING; |
601 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 649 | queue_work(system_nrt_wq, &shdlc->sm_work); |
602 | } | 650 | } |
603 | 651 | ||
604 | nfc_shdlc_handle_rcv_queue(shdlc); | 652 | llc_shdlc_handle_rcv_queue(shdlc); |
605 | 653 | ||
606 | if (shdlc->hard_fault) { | 654 | if (shdlc->hard_fault) { |
607 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | 655 | llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); |
608 | break; | 656 | break; |
609 | } | 657 | } |
610 | break; | 658 | break; |
659 | case SHDLC_HALF_CONNECTED: | ||
611 | case SHDLC_CONNECTED: | 660 | case SHDLC_CONNECTED: |
612 | nfc_shdlc_handle_rcv_queue(shdlc); | 661 | llc_shdlc_handle_rcv_queue(shdlc); |
613 | nfc_shdlc_handle_send_queue(shdlc); | 662 | llc_shdlc_handle_send_queue(shdlc); |
614 | 663 | ||
615 | if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { | 664 | if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { |
616 | pr_debug | 665 | pr_debug |
617 | ("Handle T1(send ack) elapsed (T1 now inactive)\n"); | 666 | ("Handle T1(send ack) elapsed (T1 now inactive)\n"); |
618 | 667 | ||
619 | shdlc->t1_active = false; | 668 | shdlc->t1_active = false; |
620 | r = nfc_shdlc_send_s_frame(shdlc, S_FRAME_RR, | 669 | r = llc_shdlc_send_s_frame(shdlc, S_FRAME_RR, |
621 | shdlc->nr); | 670 | shdlc->nr); |
622 | if (r < 0) | 671 | if (r < 0) |
623 | shdlc->hard_fault = r; | 672 | shdlc->hard_fault = r; |
@@ -629,12 +678,12 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
629 | 678 | ||
630 | shdlc->t2_active = false; | 679 | shdlc->t2_active = false; |
631 | 680 | ||
632 | nfc_shdlc_requeue_ack_pending(shdlc); | 681 | llc_shdlc_requeue_ack_pending(shdlc); |
633 | nfc_shdlc_handle_send_queue(shdlc); | 682 | llc_shdlc_handle_send_queue(shdlc); |
634 | } | 683 | } |
635 | 684 | ||
636 | if (shdlc->hard_fault) { | 685 | if (shdlc->hard_fault) { |
637 | nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); | 686 | shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault); |
638 | } | 687 | } |
639 | break; | 688 | break; |
640 | default: | 689 | default: |
@@ -647,7 +696,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
647 | * Called from syscall context to establish shdlc link. Sleeps until | 696 | * Called from syscall context to establish shdlc link. Sleeps until |
648 | * link is ready or failure. | 697 | * link is ready or failure. |
649 | */ | 698 | */ |
650 | static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) | 699 | static int llc_shdlc_connect(struct llc_shdlc *shdlc) |
651 | { | 700 | { |
652 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); | 701 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); |
653 | 702 | ||
@@ -662,14 +711,14 @@ static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) | |||
662 | 711 | ||
663 | mutex_unlock(&shdlc->state_mutex); | 712 | mutex_unlock(&shdlc->state_mutex); |
664 | 713 | ||
665 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 714 | queue_work(system_nrt_wq, &shdlc->sm_work); |
666 | 715 | ||
667 | wait_event(connect_wq, shdlc->connect_result != 1); | 716 | wait_event(connect_wq, shdlc->connect_result != 1); |
668 | 717 | ||
669 | return shdlc->connect_result; | 718 | return shdlc->connect_result; |
670 | } | 719 | } |
671 | 720 | ||
672 | static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | 721 | static void llc_shdlc_disconnect(struct llc_shdlc *shdlc) |
673 | { | 722 | { |
674 | pr_debug("\n"); | 723 | pr_debug("\n"); |
675 | 724 | ||
@@ -679,7 +728,7 @@ static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | |||
679 | 728 | ||
680 | mutex_unlock(&shdlc->state_mutex); | 729 | mutex_unlock(&shdlc->state_mutex); |
681 | 730 | ||
682 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 731 | queue_work(system_nrt_wq, &shdlc->sm_work); |
683 | } | 732 | } |
684 | 733 | ||
685 | /* | 734 | /* |
@@ -687,7 +736,7 @@ static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | |||
687 | * skb contains only LLC header and payload. | 736 | * skb contains only LLC header and payload. |
688 | * If skb == NULL, it is a notification that the link below is dead. | 737 | * If skb == NULL, it is a notification that the link below is dead. |
689 | */ | 738 | */ |
690 | void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) | 739 | static void llc_shdlc_recv_frame(struct llc_shdlc *shdlc, struct sk_buff *skb) |
691 | { | 740 | { |
692 | if (skb == NULL) { | 741 | if (skb == NULL) { |
693 | pr_err("NULL Frame -> link is dead\n"); | 742 | pr_err("NULL Frame -> link is dead\n"); |
@@ -697,176 +746,37 @@ void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) | |||
697 | skb_queue_tail(&shdlc->rcv_q, skb); | 746 | skb_queue_tail(&shdlc->rcv_q, skb); |
698 | } | 747 | } |
699 | 748 | ||
700 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 749 | queue_work(system_nrt_wq, &shdlc->sm_work); |
701 | } | ||
702 | EXPORT_SYMBOL(nfc_shdlc_recv_frame); | ||
703 | |||
704 | static int nfc_shdlc_open(struct nfc_hci_dev *hdev) | ||
705 | { | ||
706 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
707 | int r; | ||
708 | |||
709 | pr_debug("\n"); | ||
710 | |||
711 | if (shdlc->ops->open) { | ||
712 | r = shdlc->ops->open(shdlc); | ||
713 | if (r < 0) | ||
714 | return r; | ||
715 | } | ||
716 | |||
717 | r = nfc_shdlc_connect(shdlc); | ||
718 | if (r < 0 && shdlc->ops->close) | ||
719 | shdlc->ops->close(shdlc); | ||
720 | |||
721 | return r; | ||
722 | } | ||
723 | |||
724 | static void nfc_shdlc_close(struct nfc_hci_dev *hdev) | ||
725 | { | ||
726 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
727 | |||
728 | pr_debug("\n"); | ||
729 | |||
730 | nfc_shdlc_disconnect(shdlc); | ||
731 | |||
732 | if (shdlc->ops->close) | ||
733 | shdlc->ops->close(shdlc); | ||
734 | } | 750 | } |
735 | 751 | ||
736 | static int nfc_shdlc_hci_ready(struct nfc_hci_dev *hdev) | 752 | static void *llc_shdlc_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, |
753 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
754 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
755 | llc_failure_t llc_failure) | ||
737 | { | 756 | { |
738 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | 757 | struct llc_shdlc *shdlc; |
739 | int r = 0; | ||
740 | |||
741 | pr_debug("\n"); | ||
742 | 758 | ||
743 | if (shdlc->ops->hci_ready) | 759 | *rx_headroom = SHDLC_LLC_HEAD_ROOM; |
744 | r = shdlc->ops->hci_ready(shdlc); | 760 | *rx_tailroom = 0; |
745 | |||
746 | return r; | ||
747 | } | ||
748 | |||
749 | static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
750 | { | ||
751 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
752 | |||
753 | SHDLC_DUMP_SKB("queuing HCP packet to shdlc", skb); | ||
754 | |||
755 | skb_queue_tail(&shdlc->send_q, skb); | ||
756 | 761 | ||
757 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 762 | shdlc = kzalloc(sizeof(struct llc_shdlc), GFP_KERNEL); |
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, | ||
763 | u32 im_protocols, u32 tm_protocols) | ||
764 | { | ||
765 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
766 | |||
767 | pr_debug("\n"); | ||
768 | |||
769 | if (shdlc->ops->start_poll) | ||
770 | return shdlc->ops->start_poll(shdlc, | ||
771 | im_protocols, tm_protocols); | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int nfc_shdlc_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, | ||
777 | struct nfc_target *target) | ||
778 | { | ||
779 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
780 | |||
781 | if (shdlc->ops->target_from_gate) | ||
782 | return shdlc->ops->target_from_gate(shdlc, gate, target); | ||
783 | |||
784 | return -EPERM; | ||
785 | } | ||
786 | |||
787 | static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev, | ||
788 | u8 gate, | ||
789 | struct nfc_target *target) | ||
790 | { | ||
791 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
792 | |||
793 | pr_debug("\n"); | ||
794 | |||
795 | if (shdlc->ops->complete_target_discovered) | ||
796 | return shdlc->ops->complete_target_discovered(shdlc, gate, | ||
797 | target); | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, | ||
803 | struct nfc_target *target, | ||
804 | struct sk_buff *skb, | ||
805 | struct sk_buff **res_skb) | ||
806 | { | ||
807 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
808 | |||
809 | if (shdlc->ops->data_exchange) | ||
810 | return shdlc->ops->data_exchange(shdlc, target, skb, res_skb); | ||
811 | |||
812 | return -EPERM; | ||
813 | } | ||
814 | |||
815 | static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, | ||
816 | struct nfc_target *target) | ||
817 | { | ||
818 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
819 | |||
820 | if (shdlc->ops->check_presence) | ||
821 | return shdlc->ops->check_presence(shdlc, target); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static struct nfc_hci_ops shdlc_ops = { | ||
827 | .open = nfc_shdlc_open, | ||
828 | .close = nfc_shdlc_close, | ||
829 | .hci_ready = nfc_shdlc_hci_ready, | ||
830 | .xmit = nfc_shdlc_xmit, | ||
831 | .start_poll = nfc_shdlc_start_poll, | ||
832 | .target_from_gate = nfc_shdlc_target_from_gate, | ||
833 | .complete_target_discovered = nfc_shdlc_complete_target_discovered, | ||
834 | .data_exchange = nfc_shdlc_data_exchange, | ||
835 | .check_presence = nfc_shdlc_check_presence, | ||
836 | }; | ||
837 | |||
838 | struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | ||
839 | struct nfc_hci_init_data *init_data, | ||
840 | u32 protocols, | ||
841 | int tx_headroom, int tx_tailroom, | ||
842 | int max_link_payload, const char *devname) | ||
843 | { | ||
844 | struct nfc_shdlc *shdlc; | ||
845 | int r; | ||
846 | char name[32]; | ||
847 | |||
848 | if (ops->xmit == NULL) | ||
849 | return NULL; | ||
850 | |||
851 | shdlc = kzalloc(sizeof(struct nfc_shdlc), GFP_KERNEL); | ||
852 | if (shdlc == NULL) | 763 | if (shdlc == NULL) |
853 | return NULL; | 764 | return NULL; |
854 | 765 | ||
855 | mutex_init(&shdlc->state_mutex); | 766 | mutex_init(&shdlc->state_mutex); |
856 | shdlc->ops = ops; | ||
857 | shdlc->state = SHDLC_DISCONNECTED; | 767 | shdlc->state = SHDLC_DISCONNECTED; |
858 | 768 | ||
859 | init_timer(&shdlc->connect_timer); | 769 | init_timer(&shdlc->connect_timer); |
860 | shdlc->connect_timer.data = (unsigned long)shdlc; | 770 | shdlc->connect_timer.data = (unsigned long)shdlc; |
861 | shdlc->connect_timer.function = nfc_shdlc_connect_timeout; | 771 | shdlc->connect_timer.function = llc_shdlc_connect_timeout; |
862 | 772 | ||
863 | init_timer(&shdlc->t1_timer); | 773 | init_timer(&shdlc->t1_timer); |
864 | shdlc->t1_timer.data = (unsigned long)shdlc; | 774 | shdlc->t1_timer.data = (unsigned long)shdlc; |
865 | shdlc->t1_timer.function = nfc_shdlc_t1_timeout; | 775 | shdlc->t1_timer.function = llc_shdlc_t1_timeout; |
866 | 776 | ||
867 | init_timer(&shdlc->t2_timer); | 777 | init_timer(&shdlc->t2_timer); |
868 | shdlc->t2_timer.data = (unsigned long)shdlc; | 778 | shdlc->t2_timer.data = (unsigned long)shdlc; |
869 | shdlc->t2_timer.function = nfc_shdlc_t2_timeout; | 779 | shdlc->t2_timer.function = llc_shdlc_t2_timeout; |
870 | 780 | ||
871 | shdlc->w = SHDLC_MAX_WINDOW; | 781 | shdlc->w = SHDLC_MAX_WINDOW; |
872 | shdlc->srej_support = SHDLC_SREJ_SUPPORT; | 782 | shdlc->srej_support = SHDLC_SREJ_SUPPORT; |
@@ -875,77 +785,73 @@ struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | |||
875 | skb_queue_head_init(&shdlc->send_q); | 785 | skb_queue_head_init(&shdlc->send_q); |
876 | skb_queue_head_init(&shdlc->ack_pending_q); | 786 | skb_queue_head_init(&shdlc->ack_pending_q); |
877 | 787 | ||
878 | INIT_WORK(&shdlc->sm_work, nfc_shdlc_sm_work); | 788 | INIT_WORK(&shdlc->sm_work, llc_shdlc_sm_work); |
879 | snprintf(name, sizeof(name), "%s_shdlc_sm_wq", devname); | ||
880 | shdlc->sm_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
881 | WQ_MEM_RECLAIM, 1); | ||
882 | if (shdlc->sm_wq == NULL) | ||
883 | goto err_allocwq; | ||
884 | 789 | ||
885 | shdlc->client_headroom = tx_headroom; | 790 | shdlc->hdev = hdev; |
886 | shdlc->client_tailroom = tx_tailroom; | 791 | shdlc->xmit_to_drv = xmit_to_drv; |
887 | 792 | shdlc->rcv_to_hci = rcv_to_hci; | |
888 | shdlc->hdev = nfc_hci_allocate_device(&shdlc_ops, init_data, protocols, | 793 | shdlc->tx_headroom = tx_headroom; |
889 | tx_headroom + SHDLC_LLC_HEAD_ROOM, | 794 | shdlc->tx_tailroom = tx_tailroom; |
890 | tx_tailroom + SHDLC_LLC_TAIL_ROOM, | 795 | shdlc->llc_failure = llc_failure; |
891 | max_link_payload); | ||
892 | if (shdlc->hdev == NULL) | ||
893 | goto err_allocdev; | ||
894 | |||
895 | nfc_hci_set_clientdata(shdlc->hdev, shdlc); | ||
896 | |||
897 | r = nfc_hci_register_device(shdlc->hdev); | ||
898 | if (r < 0) | ||
899 | goto err_regdev; | ||
900 | 796 | ||
901 | return shdlc; | 797 | return shdlc; |
798 | } | ||
902 | 799 | ||
903 | err_regdev: | 800 | static void llc_shdlc_deinit(struct nfc_llc *llc) |
904 | nfc_hci_free_device(shdlc->hdev); | 801 | { |
802 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); | ||
905 | 803 | ||
906 | err_allocdev: | 804 | skb_queue_purge(&shdlc->rcv_q); |
907 | destroy_workqueue(shdlc->sm_wq); | 805 | skb_queue_purge(&shdlc->send_q); |
806 | skb_queue_purge(&shdlc->ack_pending_q); | ||
908 | 807 | ||
909 | err_allocwq: | ||
910 | kfree(shdlc); | 808 | kfree(shdlc); |
911 | |||
912 | return NULL; | ||
913 | } | 809 | } |
914 | EXPORT_SYMBOL(nfc_shdlc_allocate); | ||
915 | 810 | ||
916 | void nfc_shdlc_free(struct nfc_shdlc *shdlc) | 811 | static int llc_shdlc_start(struct nfc_llc *llc) |
917 | { | 812 | { |
918 | pr_debug("\n"); | 813 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
919 | 814 | ||
920 | nfc_hci_unregister_device(shdlc->hdev); | 815 | return llc_shdlc_connect(shdlc); |
921 | nfc_hci_free_device(shdlc->hdev); | 816 | } |
922 | 817 | ||
923 | destroy_workqueue(shdlc->sm_wq); | 818 | static int llc_shdlc_stop(struct nfc_llc *llc) |
819 | { | ||
820 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); | ||
924 | 821 | ||
925 | skb_queue_purge(&shdlc->rcv_q); | 822 | llc_shdlc_disconnect(shdlc); |
926 | skb_queue_purge(&shdlc->send_q); | ||
927 | skb_queue_purge(&shdlc->ack_pending_q); | ||
928 | 823 | ||
929 | kfree(shdlc); | 824 | return 0; |
930 | } | 825 | } |
931 | EXPORT_SYMBOL(nfc_shdlc_free); | ||
932 | 826 | ||
933 | void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata) | 827 | static void llc_shdlc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) |
934 | { | 828 | { |
935 | pr_debug("\n"); | 829 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
936 | 830 | ||
937 | shdlc->clientdata = clientdata; | 831 | llc_shdlc_recv_frame(shdlc, skb); |
938 | } | 832 | } |
939 | EXPORT_SYMBOL(nfc_shdlc_set_clientdata); | ||
940 | 833 | ||
941 | void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc) | 834 | static int llc_shdlc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) |
942 | { | 835 | { |
943 | return shdlc->clientdata; | 836 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
837 | |||
838 | skb_queue_tail(&shdlc->send_q, skb); | ||
839 | |||
840 | queue_work(system_nrt_wq, &shdlc->sm_work); | ||
841 | |||
842 | return 0; | ||
944 | } | 843 | } |
945 | EXPORT_SYMBOL(nfc_shdlc_get_clientdata); | ||
946 | 844 | ||
947 | struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc) | 845 | static struct nfc_llc_ops llc_shdlc_ops = { |
846 | .init = llc_shdlc_init, | ||
847 | .deinit = llc_shdlc_deinit, | ||
848 | .start = llc_shdlc_start, | ||
849 | .stop = llc_shdlc_stop, | ||
850 | .rcv_from_drv = llc_shdlc_rcv_from_drv, | ||
851 | .xmit_from_hci = llc_shdlc_xmit_from_hci, | ||
852 | }; | ||
853 | |||
854 | int nfc_llc_shdlc_register(void) | ||
948 | { | 855 | { |
949 | return shdlc->hdev; | 856 | return nfc_llc_register(LLC_SHDLC_NAME, &llc_shdlc_ops); |
950 | } | 857 | } |
951 | EXPORT_SYMBOL(nfc_shdlc_get_hci_dev); | ||
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index b982b5b890d7..c45ccd6c094c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -312,6 +312,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) | |||
312 | 312 | ||
313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); | 313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); |
314 | 314 | ||
315 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX); | ||
316 | |||
315 | return nfc_data_exchange(dev, local->target_idx, skb, | 317 | return nfc_data_exchange(dev, local->target_idx, skb, |
316 | nfc_llcp_recv, local); | 318 | nfc_llcp_recv, local); |
317 | } | 319 | } |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 82f0f7588b46..c12c5ef3d036 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -56,7 +56,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { | 56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { |
57 | llcp_sock = nfc_llcp_sock(sk); | 57 | llcp_sock = nfc_llcp_sock(sk); |
58 | 58 | ||
59 | lock_sock(sk); | 59 | bh_lock_sock(sk); |
60 | 60 | ||
61 | if (sk->sk_state == LLCP_CONNECTED) | 61 | if (sk->sk_state == LLCP_CONNECTED) |
62 | nfc_put_device(llcp_sock->dev); | 62 | nfc_put_device(llcp_sock->dev); |
@@ -68,26 +68,26 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, | 68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, |
69 | accept_queue) { | 69 | accept_queue) { |
70 | accept_sk = &lsk->sk; | 70 | accept_sk = &lsk->sk; |
71 | lock_sock(accept_sk); | 71 | bh_lock_sock(accept_sk); |
72 | 72 | ||
73 | nfc_llcp_accept_unlink(accept_sk); | 73 | nfc_llcp_accept_unlink(accept_sk); |
74 | 74 | ||
75 | accept_sk->sk_state = LLCP_CLOSED; | 75 | accept_sk->sk_state = LLCP_CLOSED; |
76 | 76 | ||
77 | release_sock(accept_sk); | 77 | bh_unlock_sock(accept_sk); |
78 | 78 | ||
79 | sock_orphan(accept_sk); | 79 | sock_orphan(accept_sk); |
80 | } | 80 | } |
81 | 81 | ||
82 | if (listen == true) { | 82 | if (listen == true) { |
83 | release_sock(sk); | 83 | bh_unlock_sock(sk); |
84 | continue; | 84 | continue; |
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | sk->sk_state = LLCP_CLOSED; | 88 | sk->sk_state = LLCP_CLOSED; |
89 | 89 | ||
90 | release_sock(sk); | 90 | bh_unlock_sock(sk); |
91 | 91 | ||
92 | sock_orphan(sk); | 92 | sock_orphan(sk); |
93 | 93 | ||
@@ -114,9 +114,9 @@ static void local_release(struct kref *ref) | |||
114 | nfc_llcp_socket_release(local, false); | 114 | nfc_llcp_socket_release(local, false); |
115 | del_timer_sync(&local->link_timer); | 115 | del_timer_sync(&local->link_timer); |
116 | skb_queue_purge(&local->tx_queue); | 116 | skb_queue_purge(&local->tx_queue); |
117 | destroy_workqueue(local->tx_wq); | 117 | cancel_work_sync(&local->tx_work); |
118 | destroy_workqueue(local->rx_wq); | 118 | cancel_work_sync(&local->rx_work); |
119 | destroy_workqueue(local->timeout_wq); | 119 | cancel_work_sync(&local->timeout_work); |
120 | kfree_skb(local->rx_pending); | 120 | kfree_skb(local->rx_pending); |
121 | kfree(local); | 121 | kfree(local); |
122 | } | 122 | } |
@@ -181,7 +181,7 @@ static void nfc_llcp_symm_timer(unsigned long data) | |||
181 | 181 | ||
182 | pr_err("SYMM timeout\n"); | 182 | pr_err("SYMM timeout\n"); |
183 | 183 | ||
184 | queue_work(local->timeout_wq, &local->timeout_work); | 184 | queue_work(system_nrt_wq, &local->timeout_work); |
185 | } | 185 | } |
186 | 186 | ||
187 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) | 187 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) |
@@ -426,6 +426,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
426 | u8 *miux_tlv, miux_length; | 426 | u8 *miux_tlv, miux_length; |
427 | __be16 miux; | 427 | __be16 miux; |
428 | u8 gb_len = 0; | 428 | u8 gb_len = 0; |
429 | int ret = 0; | ||
429 | 430 | ||
430 | version = LLCP_VERSION_11; | 431 | version = LLCP_VERSION_11; |
431 | version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, | 432 | version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, |
@@ -450,8 +451,8 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
450 | gb_len += ARRAY_SIZE(llcp_magic); | 451 | gb_len += ARRAY_SIZE(llcp_magic); |
451 | 452 | ||
452 | if (gb_len > NFC_MAX_GT_LEN) { | 453 | if (gb_len > NFC_MAX_GT_LEN) { |
453 | kfree(version_tlv); | 454 | ret = -EINVAL; |
454 | return -EINVAL; | 455 | goto out; |
455 | } | 456 | } |
456 | 457 | ||
457 | gb_cur = local->gb; | 458 | gb_cur = local->gb; |
@@ -471,12 +472,15 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
471 | memcpy(gb_cur, miux_tlv, miux_length); | 472 | memcpy(gb_cur, miux_tlv, miux_length); |
472 | gb_cur += miux_length; | 473 | gb_cur += miux_length; |
473 | 474 | ||
475 | local->gb_len = gb_len; | ||
476 | |||
477 | out: | ||
474 | kfree(version_tlv); | 478 | kfree(version_tlv); |
475 | kfree(lto_tlv); | 479 | kfree(lto_tlv); |
480 | kfree(wks_tlv); | ||
481 | kfree(miux_tlv); | ||
476 | 482 | ||
477 | local->gb_len = gb_len; | 483 | return ret; |
478 | |||
479 | return 0; | ||
480 | } | 484 | } |
481 | 485 | ||
482 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | 486 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) |
@@ -554,6 +558,46 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) | |||
554 | sock->recv_ack_n = (sock->recv_n - 1) % 16; | 558 | sock->recv_ack_n = (sock->recv_n - 1) % 16; |
555 | } | 559 | } |
556 | 560 | ||
561 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
562 | struct sk_buff *skb, u8 direction) | ||
563 | { | ||
564 | struct hlist_node *node; | ||
565 | struct sk_buff *skb_copy = NULL, *nskb; | ||
566 | struct sock *sk; | ||
567 | u8 *data; | ||
568 | |||
569 | read_lock(&local->raw_sockets.lock); | ||
570 | |||
571 | sk_for_each(sk, node, &local->raw_sockets.head) { | ||
572 | if (sk->sk_state != LLCP_BOUND) | ||
573 | continue; | ||
574 | |||
575 | if (skb_copy == NULL) { | ||
576 | skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE, | ||
577 | GFP_ATOMIC); | ||
578 | |||
579 | if (skb_copy == NULL) | ||
580 | continue; | ||
581 | |||
582 | data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE); | ||
583 | |||
584 | data[0] = local->dev ? local->dev->idx : 0xFF; | ||
585 | data[1] = direction; | ||
586 | } | ||
587 | |||
588 | nskb = skb_clone(skb_copy, GFP_ATOMIC); | ||
589 | if (!nskb) | ||
590 | continue; | ||
591 | |||
592 | if (sock_queue_rcv_skb(sk, nskb)) | ||
593 | kfree_skb(nskb); | ||
594 | } | ||
595 | |||
596 | read_unlock(&local->raw_sockets.lock); | ||
597 | |||
598 | kfree_skb(skb_copy); | ||
599 | } | ||
600 | |||
557 | static void nfc_llcp_tx_work(struct work_struct *work) | 601 | static void nfc_llcp_tx_work(struct work_struct *work) |
558 | { | 602 | { |
559 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 603 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, |
@@ -574,6 +618,9 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
574 | DUMP_PREFIX_OFFSET, 16, 1, | 618 | DUMP_PREFIX_OFFSET, 16, 1, |
575 | skb->data, skb->len, true); | 619 | skb->data, skb->len, true); |
576 | 620 | ||
621 | nfc_llcp_send_to_raw_sock(local, skb, | ||
622 | NFC_LLCP_DIRECTION_TX); | ||
623 | |||
577 | ret = nfc_data_exchange(local->dev, local->target_idx, | 624 | ret = nfc_data_exchange(local->dev, local->target_idx, |
578 | skb, nfc_llcp_recv, local); | 625 | skb, nfc_llcp_recv, local); |
579 | 626 | ||
@@ -1018,6 +1065,8 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1018 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, | 1065 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, |
1019 | 16, 1, skb->data, skb->len, true); | 1066 | 16, 1, skb->data, skb->len, true); |
1020 | 1067 | ||
1068 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | ||
1069 | |||
1021 | switch (ptype) { | 1070 | switch (ptype) { |
1022 | case LLCP_PDU_SYMM: | 1071 | case LLCP_PDU_SYMM: |
1023 | pr_debug("SYMM\n"); | 1072 | pr_debug("SYMM\n"); |
@@ -1052,7 +1101,7 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1052 | 1101 | ||
1053 | } | 1102 | } |
1054 | 1103 | ||
1055 | queue_work(local->tx_wq, &local->tx_work); | 1104 | queue_work(system_nrt_wq, &local->tx_work); |
1056 | kfree_skb(local->rx_pending); | 1105 | kfree_skb(local->rx_pending); |
1057 | local->rx_pending = NULL; | 1106 | local->rx_pending = NULL; |
1058 | 1107 | ||
@@ -1071,7 +1120,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err) | |||
1071 | 1120 | ||
1072 | local->rx_pending = skb_get(skb); | 1121 | local->rx_pending = skb_get(skb); |
1073 | del_timer(&local->link_timer); | 1122 | del_timer(&local->link_timer); |
1074 | queue_work(local->rx_wq, &local->rx_work); | 1123 | queue_work(system_nrt_wq, &local->rx_work); |
1075 | 1124 | ||
1076 | return; | 1125 | return; |
1077 | } | 1126 | } |
@@ -1086,7 +1135,7 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) | |||
1086 | 1135 | ||
1087 | local->rx_pending = skb_get(skb); | 1136 | local->rx_pending = skb_get(skb); |
1088 | del_timer(&local->link_timer); | 1137 | del_timer(&local->link_timer); |
1089 | queue_work(local->rx_wq, &local->rx_work); | 1138 | queue_work(system_nrt_wq, &local->rx_work); |
1090 | 1139 | ||
1091 | return 0; | 1140 | return 0; |
1092 | } | 1141 | } |
@@ -1121,7 +1170,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | |||
1121 | if (rf_mode == NFC_RF_INITIATOR) { | 1170 | if (rf_mode == NFC_RF_INITIATOR) { |
1122 | pr_debug("Queueing Tx work\n"); | 1171 | pr_debug("Queueing Tx work\n"); |
1123 | 1172 | ||
1124 | queue_work(local->tx_wq, &local->tx_work); | 1173 | queue_work(system_nrt_wq, &local->tx_work); |
1125 | } else { | 1174 | } else { |
1126 | mod_timer(&local->link_timer, | 1175 | mod_timer(&local->link_timer, |
1127 | jiffies + msecs_to_jiffies(local->remote_lto)); | 1176 | jiffies + msecs_to_jiffies(local->remote_lto)); |
@@ -1130,10 +1179,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | |||
1130 | 1179 | ||
1131 | int nfc_llcp_register_device(struct nfc_dev *ndev) | 1180 | int nfc_llcp_register_device(struct nfc_dev *ndev) |
1132 | { | 1181 | { |
1133 | struct device *dev = &ndev->dev; | ||
1134 | struct nfc_llcp_local *local; | 1182 | struct nfc_llcp_local *local; |
1135 | char name[32]; | ||
1136 | int err; | ||
1137 | 1183 | ||
1138 | local = kzalloc(sizeof(struct nfc_llcp_local), GFP_KERNEL); | 1184 | local = kzalloc(sizeof(struct nfc_llcp_local), GFP_KERNEL); |
1139 | if (local == NULL) | 1185 | if (local == NULL) |
@@ -1149,41 +1195,15 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1149 | 1195 | ||
1150 | skb_queue_head_init(&local->tx_queue); | 1196 | skb_queue_head_init(&local->tx_queue); |
1151 | INIT_WORK(&local->tx_work, nfc_llcp_tx_work); | 1197 | INIT_WORK(&local->tx_work, nfc_llcp_tx_work); |
1152 | snprintf(name, sizeof(name), "%s_llcp_tx_wq", dev_name(dev)); | ||
1153 | local->tx_wq = | ||
1154 | alloc_workqueue(name, | ||
1155 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1156 | 1); | ||
1157 | if (local->tx_wq == NULL) { | ||
1158 | err = -ENOMEM; | ||
1159 | goto err_local; | ||
1160 | } | ||
1161 | 1198 | ||
1162 | local->rx_pending = NULL; | 1199 | local->rx_pending = NULL; |
1163 | INIT_WORK(&local->rx_work, nfc_llcp_rx_work); | 1200 | INIT_WORK(&local->rx_work, nfc_llcp_rx_work); |
1164 | snprintf(name, sizeof(name), "%s_llcp_rx_wq", dev_name(dev)); | ||
1165 | local->rx_wq = | ||
1166 | alloc_workqueue(name, | ||
1167 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1168 | 1); | ||
1169 | if (local->rx_wq == NULL) { | ||
1170 | err = -ENOMEM; | ||
1171 | goto err_tx_wq; | ||
1172 | } | ||
1173 | 1201 | ||
1174 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); | 1202 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); |
1175 | snprintf(name, sizeof(name), "%s_llcp_timeout_wq", dev_name(dev)); | ||
1176 | local->timeout_wq = | ||
1177 | alloc_workqueue(name, | ||
1178 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1179 | 1); | ||
1180 | if (local->timeout_wq == NULL) { | ||
1181 | err = -ENOMEM; | ||
1182 | goto err_rx_wq; | ||
1183 | } | ||
1184 | 1203 | ||
1185 | local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock); | 1204 | rwlock_init(&local->sockets.lock); |
1186 | local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock); | 1205 | rwlock_init(&local->connecting_sockets.lock); |
1206 | rwlock_init(&local->raw_sockets.lock); | ||
1187 | 1207 | ||
1188 | nfc_llcp_build_gb(local); | 1208 | nfc_llcp_build_gb(local); |
1189 | 1209 | ||
@@ -1193,17 +1213,6 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1193 | list_add(&llcp_devices, &local->list); | 1213 | list_add(&llcp_devices, &local->list); |
1194 | 1214 | ||
1195 | return 0; | 1215 | return 0; |
1196 | |||
1197 | err_rx_wq: | ||
1198 | destroy_workqueue(local->rx_wq); | ||
1199 | |||
1200 | err_tx_wq: | ||
1201 | destroy_workqueue(local->tx_wq); | ||
1202 | |||
1203 | err_local: | ||
1204 | kfree(local); | ||
1205 | |||
1206 | return 0; | ||
1207 | } | 1216 | } |
1208 | 1217 | ||
1209 | void nfc_llcp_unregister_device(struct nfc_dev *dev) | 1218 | void nfc_llcp_unregister_device(struct nfc_dev *dev) |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 83b8bba5a280..fdb2d24e60bd 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -56,12 +56,9 @@ struct nfc_llcp_local { | |||
56 | 56 | ||
57 | struct timer_list link_timer; | 57 | struct timer_list link_timer; |
58 | struct sk_buff_head tx_queue; | 58 | struct sk_buff_head tx_queue; |
59 | struct workqueue_struct *tx_wq; | ||
60 | struct work_struct tx_work; | 59 | struct work_struct tx_work; |
61 | struct workqueue_struct *rx_wq; | ||
62 | struct work_struct rx_work; | 60 | struct work_struct rx_work; |
63 | struct sk_buff *rx_pending; | 61 | struct sk_buff *rx_pending; |
64 | struct workqueue_struct *timeout_wq; | ||
65 | struct work_struct timeout_work; | 62 | struct work_struct timeout_work; |
66 | 63 | ||
67 | u32 target_idx; | 64 | u32 target_idx; |
@@ -89,6 +86,7 @@ struct nfc_llcp_local { | |||
89 | /* sockets array */ | 86 | /* sockets array */ |
90 | struct llcp_sock_list sockets; | 87 | struct llcp_sock_list sockets; |
91 | struct llcp_sock_list connecting_sockets; | 88 | struct llcp_sock_list connecting_sockets; |
89 | struct llcp_sock_list raw_sockets; | ||
92 | }; | 90 | }; |
93 | 91 | ||
94 | struct nfc_llcp_sock { | 92 | struct nfc_llcp_sock { |
@@ -187,6 +185,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | |||
187 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); | 185 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); |
188 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); | 186 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); |
189 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); | 187 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); |
188 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
189 | struct sk_buff *skb, u8 direction); | ||
190 | 190 | ||
191 | /* Sock API */ | 191 | /* Sock API */ |
192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); | 192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index ddeb9aa398f0..40f056debf9a 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -142,6 +142,60 @@ error: | |||
142 | return ret; | 142 | return ret; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr, | ||
146 | int alen) | ||
147 | { | ||
148 | struct sock *sk = sock->sk; | ||
149 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
150 | struct nfc_llcp_local *local; | ||
151 | struct nfc_dev *dev; | ||
152 | struct sockaddr_nfc_llcp llcp_addr; | ||
153 | int len, ret = 0; | ||
154 | |||
155 | if (!addr || addr->sa_family != AF_NFC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
159 | |||
160 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | ||
161 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | ||
162 | memcpy(&llcp_addr, addr, len); | ||
163 | |||
164 | lock_sock(sk); | ||
165 | |||
166 | if (sk->sk_state != LLCP_CLOSED) { | ||
167 | ret = -EBADFD; | ||
168 | goto error; | ||
169 | } | ||
170 | |||
171 | dev = nfc_get_device(llcp_addr.dev_idx); | ||
172 | if (dev == NULL) { | ||
173 | ret = -ENODEV; | ||
174 | goto error; | ||
175 | } | ||
176 | |||
177 | local = nfc_llcp_find_local(dev); | ||
178 | if (local == NULL) { | ||
179 | ret = -ENODEV; | ||
180 | goto put_dev; | ||
181 | } | ||
182 | |||
183 | llcp_sock->dev = dev; | ||
184 | llcp_sock->local = nfc_llcp_local_get(local); | ||
185 | llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; | ||
186 | |||
187 | nfc_llcp_sock_link(&local->raw_sockets, sk); | ||
188 | |||
189 | sk->sk_state = LLCP_BOUND; | ||
190 | |||
191 | put_dev: | ||
192 | nfc_put_device(dev); | ||
193 | |||
194 | error: | ||
195 | release_sock(sk); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
145 | static int llcp_sock_listen(struct socket *sock, int backlog) | 199 | static int llcp_sock_listen(struct socket *sock, int backlog) |
146 | { | 200 | { |
147 | struct sock *sk = sock->sk; | 201 | struct sock *sk = sock->sk; |
@@ -300,9 +354,6 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, | |||
300 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, | 354 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, |
301 | llcp_sock->dsap, llcp_sock->ssap); | 355 | llcp_sock->dsap, llcp_sock->ssap); |
302 | 356 | ||
303 | if (llcp_sock == NULL || llcp_sock->dev == NULL) | ||
304 | return -EBADFD; | ||
305 | |||
306 | uaddr->sa_family = AF_NFC; | 357 | uaddr->sa_family = AF_NFC; |
307 | 358 | ||
308 | *len = sizeof(struct sockaddr_nfc_llcp); | 359 | *len = sizeof(struct sockaddr_nfc_llcp); |
@@ -421,7 +472,10 @@ static int llcp_sock_release(struct socket *sock) | |||
421 | 472 | ||
422 | release_sock(sk); | 473 | release_sock(sk); |
423 | 474 | ||
424 | nfc_llcp_sock_unlink(&local->sockets, sk); | 475 | if (sock->type == SOCK_RAW) |
476 | nfc_llcp_sock_unlink(&local->raw_sockets, sk); | ||
477 | else | ||
478 | nfc_llcp_sock_unlink(&local->sockets, sk); | ||
425 | 479 | ||
426 | out: | 480 | out: |
427 | sock_orphan(sk); | 481 | sock_orphan(sk); |
@@ -617,7 +671,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
617 | if (!(flags & MSG_PEEK)) { | 671 | if (!(flags & MSG_PEEK)) { |
618 | 672 | ||
619 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ | 673 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ |
620 | if (sk->sk_type == SOCK_STREAM) { | 674 | if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) { |
621 | skb_pull(skb, copied); | 675 | skb_pull(skb, copied); |
622 | if (skb->len) { | 676 | if (skb->len) { |
623 | skb_queue_head(&sk->sk_receive_queue, skb); | 677 | skb_queue_head(&sk->sk_receive_queue, skb); |
@@ -658,6 +712,26 @@ static const struct proto_ops llcp_sock_ops = { | |||
658 | .mmap = sock_no_mmap, | 712 | .mmap = sock_no_mmap, |
659 | }; | 713 | }; |
660 | 714 | ||
715 | static const struct proto_ops llcp_rawsock_ops = { | ||
716 | .family = PF_NFC, | ||
717 | .owner = THIS_MODULE, | ||
718 | .bind = llcp_raw_sock_bind, | ||
719 | .connect = sock_no_connect, | ||
720 | .release = llcp_sock_release, | ||
721 | .socketpair = sock_no_socketpair, | ||
722 | .accept = sock_no_accept, | ||
723 | .getname = llcp_sock_getname, | ||
724 | .poll = llcp_sock_poll, | ||
725 | .ioctl = sock_no_ioctl, | ||
726 | .listen = sock_no_listen, | ||
727 | .shutdown = sock_no_shutdown, | ||
728 | .setsockopt = sock_no_setsockopt, | ||
729 | .getsockopt = sock_no_getsockopt, | ||
730 | .sendmsg = sock_no_sendmsg, | ||
731 | .recvmsg = llcp_sock_recvmsg, | ||
732 | .mmap = sock_no_mmap, | ||
733 | }; | ||
734 | |||
661 | static void llcp_sock_destruct(struct sock *sk) | 735 | static void llcp_sock_destruct(struct sock *sk) |
662 | { | 736 | { |
663 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 737 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -735,10 +809,15 @@ static int llcp_sock_create(struct net *net, struct socket *sock, | |||
735 | 809 | ||
736 | pr_debug("%p\n", sock); | 810 | pr_debug("%p\n", sock); |
737 | 811 | ||
738 | if (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM) | 812 | if (sock->type != SOCK_STREAM && |
813 | sock->type != SOCK_DGRAM && | ||
814 | sock->type != SOCK_RAW) | ||
739 | return -ESOCKTNOSUPPORT; | 815 | return -ESOCKTNOSUPPORT; |
740 | 816 | ||
741 | sock->ops = &llcp_sock_ops; | 817 | if (sock->type == SOCK_RAW) |
818 | sock->ops = &llcp_rawsock_ops; | ||
819 | else | ||
820 | sock->ops = &llcp_sock_ops; | ||
742 | 821 | ||
743 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); | 822 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); |
744 | if (sk == NULL) | 823 | if (sk == NULL) |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index f81efe13985a..acf9abb7d99b 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -176,6 +176,27 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt) | |||
176 | (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); | 176 | (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); |
177 | } | 177 | } |
178 | 178 | ||
179 | struct nci_set_config_param { | ||
180 | __u8 id; | ||
181 | size_t len; | ||
182 | __u8 *val; | ||
183 | }; | ||
184 | |||
185 | static void nci_set_config_req(struct nci_dev *ndev, unsigned long opt) | ||
186 | { | ||
187 | struct nci_set_config_param *param = (struct nci_set_config_param *)opt; | ||
188 | struct nci_core_set_config_cmd cmd; | ||
189 | |||
190 | BUG_ON(param->len > NCI_MAX_PARAM_LEN); | ||
191 | |||
192 | cmd.num_params = 1; | ||
193 | cmd.param.id = param->id; | ||
194 | cmd.param.len = param->len; | ||
195 | memcpy(cmd.param.val, param->val, param->len); | ||
196 | |||
197 | nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd); | ||
198 | } | ||
199 | |||
179 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | 200 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) |
180 | { | 201 | { |
181 | struct nci_rf_disc_cmd cmd; | 202 | struct nci_rf_disc_cmd cmd; |
@@ -388,6 +409,32 @@ static int nci_dev_down(struct nfc_dev *nfc_dev) | |||
388 | return nci_close_device(ndev); | 409 | return nci_close_device(ndev); |
389 | } | 410 | } |
390 | 411 | ||
412 | static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | ||
413 | { | ||
414 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
415 | struct nci_set_config_param param; | ||
416 | __u8 local_gb[NFC_MAX_GT_LEN]; | ||
417 | int i, rc = 0; | ||
418 | |||
419 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); | ||
420 | if ((param.val == NULL) || (param.len == 0)) | ||
421 | return rc; | ||
422 | |||
423 | if (param.len > NCI_MAX_PARAM_LEN) | ||
424 | return -EINVAL; | ||
425 | |||
426 | for (i = 0; i < param.len; i++) | ||
427 | local_gb[param.len-1-i] = param.val[i]; | ||
428 | |||
429 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; | ||
430 | param.val = local_gb; | ||
431 | |||
432 | rc = nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | ||
433 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | ||
434 | |||
435 | return rc; | ||
436 | } | ||
437 | |||
391 | static int nci_start_poll(struct nfc_dev *nfc_dev, | 438 | static int nci_start_poll(struct nfc_dev *nfc_dev, |
392 | __u32 im_protocols, __u32 tm_protocols) | 439 | __u32 im_protocols, __u32 tm_protocols) |
393 | { | 440 | { |
@@ -415,6 +462,14 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, | |||
415 | return -EBUSY; | 462 | return -EBUSY; |
416 | } | 463 | } |
417 | 464 | ||
465 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { | ||
466 | rc = nci_set_local_general_bytes(nfc_dev); | ||
467 | if (rc) { | ||
468 | pr_err("failed to set local general bytes\n"); | ||
469 | return rc; | ||
470 | } | ||
471 | } | ||
472 | |||
418 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, | 473 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, |
419 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); | 474 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); |
420 | 475 | ||
@@ -509,7 +564,7 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
509 | { | 564 | { |
510 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 565 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
511 | 566 | ||
512 | pr_debug("target_idx %d\n", target->idx); | 567 | pr_debug("entry\n"); |
513 | 568 | ||
514 | if (!ndev->target_active_prot) { | 569 | if (!ndev->target_active_prot) { |
515 | pr_err("unable to deactivate target, no active target\n"); | 570 | pr_err("unable to deactivate target, no active target\n"); |
@@ -524,6 +579,38 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
524 | } | 579 | } |
525 | } | 580 | } |
526 | 581 | ||
582 | |||
583 | static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, | ||
584 | __u8 comm_mode, __u8 *gb, size_t gb_len) | ||
585 | { | ||
586 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
587 | int rc; | ||
588 | |||
589 | pr_debug("target_idx %d, comm_mode %d\n", target->idx, comm_mode); | ||
590 | |||
591 | rc = nci_activate_target(nfc_dev, target, NFC_PROTO_NFC_DEP); | ||
592 | if (rc) | ||
593 | return rc; | ||
594 | |||
595 | rc = nfc_set_remote_general_bytes(nfc_dev, ndev->remote_gb, | ||
596 | ndev->remote_gb_len); | ||
597 | if (!rc) | ||
598 | rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_PASSIVE, | ||
599 | NFC_RF_INITIATOR); | ||
600 | |||
601 | return rc; | ||
602 | } | ||
603 | |||
604 | static int nci_dep_link_down(struct nfc_dev *nfc_dev) | ||
605 | { | ||
606 | pr_debug("entry\n"); | ||
607 | |||
608 | nci_deactivate_target(nfc_dev, NULL); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | |||
527 | static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 614 | static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
528 | struct sk_buff *skb, | 615 | struct sk_buff *skb, |
529 | data_exchange_cb_t cb, void *cb_context) | 616 | data_exchange_cb_t cb, void *cb_context) |
@@ -557,6 +644,8 @@ static struct nfc_ops nci_nfc_ops = { | |||
557 | .dev_down = nci_dev_down, | 644 | .dev_down = nci_dev_down, |
558 | .start_poll = nci_start_poll, | 645 | .start_poll = nci_start_poll, |
559 | .stop_poll = nci_stop_poll, | 646 | .stop_poll = nci_stop_poll, |
647 | .dep_link_up = nci_dep_link_up, | ||
648 | .dep_link_down = nci_dep_link_down, | ||
560 | .activate_target = nci_activate_target, | 649 | .activate_target = nci_activate_target, |
561 | .deactivate_target = nci_deactivate_target, | 650 | .deactivate_target = nci_deactivate_target, |
562 | .im_transceive = nci_transceive, | 651 | .im_transceive = nci_transceive, |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index af7a93b04393..b2aa98ef0927 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -176,6 +176,8 @@ static int nci_add_new_protocol(struct nci_dev *ndev, | |||
176 | protocol = NFC_PROTO_ISO14443_B_MASK; | 176 | protocol = NFC_PROTO_ISO14443_B_MASK; |
177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) | 177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) |
178 | protocol = NFC_PROTO_FELICA_MASK; | 178 | protocol = NFC_PROTO_FELICA_MASK; |
179 | else if (rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) | ||
180 | protocol = NFC_PROTO_NFC_DEP_MASK; | ||
179 | else | 181 | else |
180 | protocol = 0; | 182 | protocol = 0; |
181 | 183 | ||
@@ -361,6 +363,33 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, | |||
361 | return NCI_STATUS_OK; | 363 | return NCI_STATUS_OK; |
362 | } | 364 | } |
363 | 365 | ||
366 | static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, | ||
367 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | ||
368 | { | ||
369 | struct activation_params_poll_nfc_dep *poll; | ||
370 | int i; | ||
371 | |||
372 | switch (ntf->activation_rf_tech_and_mode) { | ||
373 | case NCI_NFC_A_PASSIVE_POLL_MODE: | ||
374 | case NCI_NFC_F_PASSIVE_POLL_MODE: | ||
375 | poll = &ntf->activation_params.poll_nfc_dep; | ||
376 | poll->atr_res_len = min_t(__u8, *data++, 63); | ||
377 | pr_debug("atr_res_len %d\n", poll->atr_res_len); | ||
378 | if (poll->atr_res_len > 0) { | ||
379 | for (i = 0; i < poll->atr_res_len; i++) | ||
380 | poll->atr_res[poll->atr_res_len-1-i] = data[i]; | ||
381 | } | ||
382 | break; | ||
383 | |||
384 | default: | ||
385 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | ||
386 | ntf->activation_rf_tech_and_mode); | ||
387 | return NCI_STATUS_RF_PROTOCOL_ERROR; | ||
388 | } | ||
389 | |||
390 | return NCI_STATUS_OK; | ||
391 | } | ||
392 | |||
364 | static void nci_target_auto_activated(struct nci_dev *ndev, | 393 | static void nci_target_auto_activated(struct nci_dev *ndev, |
365 | struct nci_rf_intf_activated_ntf *ntf) | 394 | struct nci_rf_intf_activated_ntf *ntf) |
366 | { | 395 | { |
@@ -454,6 +483,11 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
454 | &ntf, data); | 483 | &ntf, data); |
455 | break; | 484 | break; |
456 | 485 | ||
486 | case NCI_RF_INTERFACE_NFC_DEP: | ||
487 | err = nci_extract_activation_params_nfc_dep(ndev, | ||
488 | &ntf, data); | ||
489 | break; | ||
490 | |||
457 | case NCI_RF_INTERFACE_FRAME: | 491 | case NCI_RF_INTERFACE_FRAME: |
458 | /* no activation params */ | 492 | /* no activation params */ |
459 | break; | 493 | break; |
@@ -473,6 +507,24 @@ exit: | |||
473 | 507 | ||
474 | /* set the available credits to initial value */ | 508 | /* set the available credits to initial value */ |
475 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); | 509 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); |
510 | |||
511 | /* store general bytes to be reported later in dep_link_up */ | ||
512 | if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) { | ||
513 | ndev->remote_gb_len = 0; | ||
514 | |||
515 | if (ntf.activation_params_len > 0) { | ||
516 | /* ATR_RES general bytes at offset 15 */ | ||
517 | ndev->remote_gb_len = min_t(__u8, | ||
518 | (ntf.activation_params | ||
519 | .poll_nfc_dep.atr_res_len | ||
520 | - NFC_ATR_RES_GT_OFFSET), | ||
521 | NFC_MAX_GT_LEN); | ||
522 | memcpy(ndev->remote_gb, | ||
523 | (ntf.activation_params.poll_nfc_dep | ||
524 | .atr_res + NFC_ATR_RES_GT_OFFSET), | ||
525 | ndev->remote_gb_len); | ||
526 | } | ||
527 | } | ||
476 | } | 528 | } |
477 | 529 | ||
478 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { | 530 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { |
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 3003c3390e49..dd072f38ad00 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c | |||
@@ -119,6 +119,16 @@ exit: | |||
119 | nci_req_complete(ndev, rsp_1->status); | 119 | nci_req_complete(ndev, rsp_1->status); |
120 | } | 120 | } |
121 | 121 | ||
122 | static void nci_core_set_config_rsp_packet(struct nci_dev *ndev, | ||
123 | struct sk_buff *skb) | ||
124 | { | ||
125 | struct nci_core_set_config_rsp *rsp = (void *) skb->data; | ||
126 | |||
127 | pr_debug("status 0x%x\n", rsp->status); | ||
128 | |||
129 | nci_req_complete(ndev, rsp->status); | ||
130 | } | ||
131 | |||
122 | static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, | 132 | static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, |
123 | struct sk_buff *skb) | 133 | struct sk_buff *skb) |
124 | { | 134 | { |
@@ -194,6 +204,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
194 | nci_core_init_rsp_packet(ndev, skb); | 204 | nci_core_init_rsp_packet(ndev, skb); |
195 | break; | 205 | break; |
196 | 206 | ||
207 | case NCI_OP_CORE_SET_CONFIG_RSP: | ||
208 | nci_core_set_config_rsp_packet(ndev, skb); | ||
209 | break; | ||
210 | |||
197 | case NCI_OP_RF_DISCOVER_MAP_RSP: | 211 | case NCI_OP_RF_DISCOVER_MAP_RSP: |
198 | nci_rf_disc_map_rsp_packet(ndev, skb); | 212 | nci_rf_disc_map_rsp_packet(ndev, skb); |
199 | break; | 213 | break; |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 4bbb70e32d1e..c1b5285cbde7 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -761,31 +761,63 @@ static struct genl_ops nfc_genl_ops[] = { | |||
761 | }, | 761 | }, |
762 | }; | 762 | }; |
763 | 763 | ||
764 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | 764 | |
765 | unsigned long event, void *ptr) | 765 | struct urelease_work { |
766 | struct work_struct w; | ||
767 | int portid; | ||
768 | }; | ||
769 | |||
770 | static void nfc_urelease_event_work(struct work_struct *work) | ||
766 | { | 771 | { |
767 | struct netlink_notify *n = ptr; | 772 | struct urelease_work *w = container_of(work, struct urelease_work, w); |
768 | struct class_dev_iter iter; | 773 | struct class_dev_iter iter; |
769 | struct nfc_dev *dev; | 774 | struct nfc_dev *dev; |
770 | 775 | ||
771 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | 776 | pr_debug("portid %d\n", w->portid); |
772 | goto out; | ||
773 | 777 | ||
774 | pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); | 778 | mutex_lock(&nfc_devlist_mutex); |
775 | 779 | ||
776 | nfc_device_iter_init(&iter); | 780 | nfc_device_iter_init(&iter); |
777 | dev = nfc_device_iter_next(&iter); | 781 | dev = nfc_device_iter_next(&iter); |
778 | 782 | ||
779 | while (dev) { | 783 | while (dev) { |
780 | if (dev->genl_data.poll_req_portid == n->portid) { | 784 | mutex_lock(&dev->genl_data.genl_data_mutex); |
785 | |||
786 | if (dev->genl_data.poll_req_portid == w->portid) { | ||
781 | nfc_stop_poll(dev); | 787 | nfc_stop_poll(dev); |
782 | dev->genl_data.poll_req_portid = 0; | 788 | dev->genl_data.poll_req_portid = 0; |
783 | } | 789 | } |
790 | |||
791 | mutex_unlock(&dev->genl_data.genl_data_mutex); | ||
792 | |||
784 | dev = nfc_device_iter_next(&iter); | 793 | dev = nfc_device_iter_next(&iter); |
785 | } | 794 | } |
786 | 795 | ||
787 | nfc_device_iter_exit(&iter); | 796 | nfc_device_iter_exit(&iter); |
788 | 797 | ||
798 | mutex_unlock(&nfc_devlist_mutex); | ||
799 | |||
800 | kfree(w); | ||
801 | } | ||
802 | |||
803 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | ||
804 | unsigned long event, void *ptr) | ||
805 | { | ||
806 | struct netlink_notify *n = ptr; | ||
807 | struct urelease_work *w; | ||
808 | |||
809 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | ||
810 | goto out; | ||
811 | |||
812 | pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); | ||
813 | |||
814 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | ||
815 | if (w) { | ||
816 | INIT_WORK((struct work_struct *) w, nfc_urelease_event_work); | ||
817 | w->portid = n->portid; | ||
818 | schedule_work((struct work_struct *) w); | ||
819 | } | ||
820 | |||
789 | out: | 821 | out: |
790 | return NOTIFY_DONE; | 822 | return NOTIFY_DONE; |
791 | } | 823 | } |