Merge commit 'v3.14' into next
[firefly-linux-kernel-4.4.55.git] / net / nfc / hci / llc.c
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, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <net/nfc/llc.h>
20
21 #include "llc.h"
22
23 static struct list_head llc_engines;
24
25 int nfc_llc_init(void)
26 {
27         int r;
28
29         INIT_LIST_HEAD(&llc_engines);
30
31         r = nfc_llc_nop_register();
32         if (r)
33                 goto exit;
34
35         r = nfc_llc_shdlc_register();
36         if (r)
37                 goto exit;
38
39         return 0;
40
41 exit:
42         nfc_llc_exit();
43         return r;
44 }
45
46 void nfc_llc_exit(void)
47 {
48         struct nfc_llc_engine *llc_engine, *n;
49
50         list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) {
51                 list_del(&llc_engine->entry);
52                 kfree(llc_engine->name);
53                 kfree(llc_engine);
54         }
55 }
56
57 int nfc_llc_register(const char *name, struct nfc_llc_ops *ops)
58 {
59         struct nfc_llc_engine *llc_engine;
60
61         llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL);
62         if (llc_engine == NULL)
63                 return -ENOMEM;
64
65         llc_engine->name = kstrdup(name, GFP_KERNEL);
66         if (llc_engine->name == NULL) {
67                 kfree(llc_engine);
68                 return -ENOMEM;
69         }
70         llc_engine->ops = ops;
71
72         INIT_LIST_HEAD(&llc_engine->entry);
73         list_add_tail(&llc_engine->entry, &llc_engines);
74
75         return 0;
76 }
77
78 static struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name)
79 {
80         struct nfc_llc_engine *llc_engine;
81
82         list_for_each_entry(llc_engine, &llc_engines, entry) {
83                 if (strcmp(llc_engine->name, name) == 0)
84                         return llc_engine;
85         }
86
87         return NULL;
88 }
89
90 void nfc_llc_unregister(const char *name)
91 {
92         struct nfc_llc_engine *llc_engine;
93
94         llc_engine = nfc_llc_name_to_engine(name);
95         if (llc_engine == NULL)
96                 return;
97
98         list_del(&llc_engine->entry);
99         kfree(llc_engine->name);
100         kfree(llc_engine);
101 }
102
103 struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev,
104                                  xmit_to_drv_t xmit_to_drv,
105                                  rcv_to_hci_t rcv_to_hci, int tx_headroom,
106                                  int tx_tailroom, llc_failure_t llc_failure)
107 {
108         struct nfc_llc_engine *llc_engine;
109         struct nfc_llc *llc;
110
111         llc_engine = nfc_llc_name_to_engine(name);
112         if (llc_engine == NULL)
113                 return NULL;
114
115         llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL);
116         if (llc == NULL)
117                 return NULL;
118
119         llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci,
120                                           tx_headroom, tx_tailroom,
121                                           &llc->rx_headroom, &llc->rx_tailroom,
122                                           llc_failure);
123         if (llc->data == NULL) {
124                 kfree(llc);
125                 return NULL;
126         }
127         llc->ops = llc_engine->ops;
128
129         return llc;
130 }
131
132 void nfc_llc_free(struct nfc_llc *llc)
133 {
134         llc->ops->deinit(llc);
135         kfree(llc);
136 }
137
138 inline void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom,
139                                           int *rx_tailroom)
140 {
141         *rx_headroom = llc->rx_headroom;
142         *rx_tailroom = llc->rx_tailroom;
143 }
144
145 inline int nfc_llc_start(struct nfc_llc *llc)
146 {
147         return llc->ops->start(llc);
148 }
149
150 inline int nfc_llc_stop(struct nfc_llc *llc)
151 {
152         return llc->ops->stop(llc);
153 }
154
155 inline void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb)
156 {
157         llc->ops->rcv_from_drv(llc, skb);
158 }
159
160 inline int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb)
161 {
162         return llc->ops->xmit_from_hci(llc, skb);
163 }
164
165 inline void *nfc_llc_get_data(struct nfc_llc *llc)
166 {
167         return llc->data;
168 }