1c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr/*
2c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * Copyright (C) 2011 Instituto Nokia de Tecnologia
3c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr *
4c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * Authors:
5c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
6c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
7c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr *
8c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * This program is free software; you can redistribute it and/or modify
9c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * it under the terms of the GNU General Public License as published by
10c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * the Free Software Foundation; either version 2 of the License, or
11c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * (at your option) any later version.
12c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr *
13c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * This program is distributed in the hope that it will be useful,
14c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * GNU General Public License for more details.
17c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr *
18c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr * You should have received a copy of the GNU General Public License
1998b32decc83ed3137e3ddbc918b102f8fc406b6dJeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>.
20c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr */
21c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
22c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr#include <linux/nfc.h>
233a9a231d977222eea36eae091df2c358e03ac839Paul Gortmaker#include <linux/module.h>
24c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
25c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr#include "nfc.h"
26c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
27c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrstatic DEFINE_RWLOCK(proto_tab_lock);
28c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrstatic const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX];
29c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
30c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrstatic int nfc_sock_create(struct net *net, struct socket *sock, int proto,
310a40acb24602783fcf6881f915659148aa9807d7Samuel Ortiz			   int kern)
32c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr{
33c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	int rc = -EPROTONOSUPPORT;
34c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
35c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	if (net != &init_net)
36c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		return -EAFNOSUPPORT;
37c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
38c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	if (proto < 0 || proto >= NFC_SOCKPROTO_MAX)
39c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		return -EINVAL;
40c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
41c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	read_lock(&proto_tab_lock);
42c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	if (proto_tab[proto] &&	try_module_get(proto_tab[proto]->owner)) {
43c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		rc = proto_tab[proto]->create(net, sock, proto_tab[proto]);
44c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		module_put(proto_tab[proto]->owner);
45c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	}
46c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	read_unlock(&proto_tab_lock);
47c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
48c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	return rc;
49c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr}
50c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
51c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrstatic struct net_proto_family nfc_sock_family_ops = {
52c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	.owner  = THIS_MODULE,
53c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	.family = PF_NFC,
54c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	.create = nfc_sock_create,
55c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr};
56c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
57c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrint nfc_proto_register(const struct nfc_protocol *nfc_proto)
58c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr{
59c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	int rc;
60c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
61c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	if (nfc_proto->id < 0 || nfc_proto->id >= NFC_SOCKPROTO_MAX)
62c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		return -EINVAL;
63c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
64c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	rc = proto_register(nfc_proto->proto, 0);
65c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	if (rc)
66c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		return rc;
67c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
68c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	write_lock(&proto_tab_lock);
69c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	if (proto_tab[nfc_proto->id])
70c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		rc = -EBUSY;
71c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	else
72c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr		proto_tab[nfc_proto->id] = nfc_proto;
73c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	write_unlock(&proto_tab_lock);
74c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
75c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	return rc;
76c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr}
77c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida JrEXPORT_SYMBOL(nfc_proto_register);
78c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
79c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrvoid nfc_proto_unregister(const struct nfc_protocol *nfc_proto)
80c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr{
81c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	write_lock(&proto_tab_lock);
82c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	proto_tab[nfc_proto->id] = NULL;
83c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	write_unlock(&proto_tab_lock);
84c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
85c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	proto_unregister(nfc_proto->proto);
86c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr}
87c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida JrEXPORT_SYMBOL(nfc_proto_unregister);
88c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
89c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrint __init af_nfc_init(void)
90c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr{
91c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	return sock_register(&nfc_sock_family_ops);
92c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr}
93c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr
94c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jrvoid af_nfc_exit(void)
95c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr{
96c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr	sock_unregister(PF_NFC);
97c7fe3b52c1283b8ba810eb6ecddf1c8a0bcc13abAloisio Almeida Jr}
98