167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade/*
267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * Link Layer Control manager
367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade *
467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * Copyright (C) 2012  Intel Corporation. All rights reserved.
567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade *
667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * This program is free software; you can redistribute it and/or modify it
767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * under the terms and conditions of the GNU General Public License,
867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * version 2, as published by the Free Software Foundation.
967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade *
1067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * This program is distributed in the hope that it will be useful,
1167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * but WITHOUT ANY WARRANTY; without even the implied warranty of
1267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * GNU General Public License for more details.
1467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade *
1567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade * You should have received a copy of the GNU General Public License
1698b32decc83ed3137e3ddbc918b102f8fc406b6dJeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>.
1767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade */
1867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
1967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade#include <net/nfc/llc.h>
20f4f20d0650e9cd13f65b5e7f93af126b526af721Samuel Ortiz
2167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade#include "llc.h"
2267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
230b51fc5633df563695f5021bc121a9df20b3eb14Axel Linstatic LIST_HEAD(llc_engines);
2467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
2567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeint nfc_llc_init(void)
2667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
274a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	int r;
284a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade
294a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	r = nfc_llc_nop_register();
304a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	if (r)
314a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade		goto exit;
324a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade
334a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	r = nfc_llc_shdlc_register();
344a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	if (r)
354a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade		goto exit;
364a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade
374a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	return 0;
384a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade
394a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyadeexit:
404a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	nfc_llc_exit();
414a61cd6687fc6348d08724676d34e38160d6cf9bEric Lapuyade	return r;
4267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
4367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
4467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadevoid nfc_llc_exit(void)
4567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
4667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	struct nfc_llc_engine *llc_engine, *n;
4767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
4867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) {
4967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		list_del(&llc_engine->entry);
5067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		kfree(llc_engine->name);
5167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		kfree(llc_engine);
5267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	}
5367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
5467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
5567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeint nfc_llc_register(const char *name, struct nfc_llc_ops *ops)
5667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
5767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	struct nfc_llc_engine *llc_engine;
5867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
5967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL);
6067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	if (llc_engine == NULL)
6167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		return -ENOMEM;
6267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
6367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc_engine->name = kstrdup(name, GFP_KERNEL);
6467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	if (llc_engine->name == NULL) {
6567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		kfree(llc_engine);
6667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		return -ENOMEM;
6767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	}
6867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc_engine->ops = ops;
6967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
7067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	INIT_LIST_HEAD(&llc_engine->entry);
710f450772224f99db3b8384bfb8f751889d0c4cb8Szymon Janc	list_add_tail(&llc_engine->entry, &llc_engines);
7267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
7367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return 0;
7467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
7567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
7667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadestatic struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name)
7767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
7867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	struct nfc_llc_engine *llc_engine;
7967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
8067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	list_for_each_entry(llc_engine, &llc_engines, entry) {
8167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		if (strcmp(llc_engine->name, name) == 0)
8267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade			return llc_engine;
8367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	}
8467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
8567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return NULL;
8667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
8767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
8867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadevoid nfc_llc_unregister(const char *name)
8967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
9067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	struct nfc_llc_engine *llc_engine;
9167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
9267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc_engine = nfc_llc_name_to_engine(name);
9367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	if (llc_engine == NULL)
9467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		return;
9567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
9667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	list_del(&llc_engine->entry);
9767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	kfree(llc_engine->name);
9867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	kfree(llc_engine);
9967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
10067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
10167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadestruct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev,
10267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade				 xmit_to_drv_t xmit_to_drv,
10367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade				 rcv_to_hci_t rcv_to_hci, int tx_headroom,
10467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade				 int tx_tailroom, llc_failure_t llc_failure)
10567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
10667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	struct nfc_llc_engine *llc_engine;
10767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	struct nfc_llc *llc;
10867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
10967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc_engine = nfc_llc_name_to_engine(name);
11067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	if (llc_engine == NULL)
11167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		return NULL;
11267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
11367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL);
11467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	if (llc == NULL)
11567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		return NULL;
11667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
11767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci,
11867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade					  tx_headroom, tx_tailroom,
11967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade					  &llc->rx_headroom, &llc->rx_tailroom,
12067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade					  llc_failure);
12167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	if (llc->data == NULL) {
12267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		kfree(llc);
12367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade		return NULL;
12467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	}
12567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc->ops = llc_engine->ops;
12667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
12767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return llc;
12867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
12967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
13067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadevoid nfc_llc_free(struct nfc_llc *llc)
13167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
13267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc->ops->deinit(llc);
13367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	kfree(llc);
13467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
13567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
13667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeinline void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom,
13767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade					  int *rx_tailroom)
13867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
13967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	*rx_headroom = llc->rx_headroom;
14067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	*rx_tailroom = llc->rx_tailroom;
14167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
14267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
14367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeinline int nfc_llc_start(struct nfc_llc *llc)
14467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
14567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return llc->ops->start(llc);
14667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
14767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
14867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeinline int nfc_llc_stop(struct nfc_llc *llc)
14967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
15067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return llc->ops->stop(llc);
15167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
15267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
15367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeinline void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb)
15467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
15567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	llc->ops->rcv_from_drv(llc, skb);
15667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
15767cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
15867cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeinline int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb)
15967cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
16067cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return llc->ops->xmit_from_hci(llc, skb);
16167cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
16267cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade
16367cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyadeinline void *nfc_llc_get_data(struct nfc_llc *llc)
16467cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade{
16567cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade	return llc->data;
16667cccfe17d1b3da1ed6c79e643c9be95ebde9642Eric Lapuyade}
167