diff options
Diffstat (limited to 'net/nfc/hci')
-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 |
9 files changed, 799 insertions, 489 deletions
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); | ||