18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 Instituto Nokia de Tecnologia 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> 78c2ecf20Sopenharmony_ci * Lauro Ramos Venancio <lauro.venancio@openbossa.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/nfc.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "nfc.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(proto_tab_lock); 168c2ecf20Sopenharmony_cistatic const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX]; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int nfc_sock_create(struct net *net, struct socket *sock, int proto, 198c2ecf20Sopenharmony_ci int kern) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci int rc = -EPROTONOSUPPORT; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (net != &init_net) 248c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (proto < 0 || proto >= NFC_SOCKPROTO_MAX) 278c2ecf20Sopenharmony_ci return -EINVAL; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci read_lock(&proto_tab_lock); 308c2ecf20Sopenharmony_ci if (proto_tab[proto] && try_module_get(proto_tab[proto]->owner)) { 318c2ecf20Sopenharmony_ci rc = proto_tab[proto]->create(net, sock, proto_tab[proto], kern); 328c2ecf20Sopenharmony_ci module_put(proto_tab[proto]->owner); 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci read_unlock(&proto_tab_lock); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return rc; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct net_proto_family nfc_sock_family_ops = { 408c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 418c2ecf20Sopenharmony_ci .family = PF_NFC, 428c2ecf20Sopenharmony_ci .create = nfc_sock_create, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint nfc_proto_register(const struct nfc_protocol *nfc_proto) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int rc; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (nfc_proto->id < 0 || nfc_proto->id >= NFC_SOCKPROTO_MAX) 508c2ecf20Sopenharmony_ci return -EINVAL; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci rc = proto_register(nfc_proto->proto, 0); 538c2ecf20Sopenharmony_ci if (rc) 548c2ecf20Sopenharmony_ci return rc; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci write_lock(&proto_tab_lock); 578c2ecf20Sopenharmony_ci if (proto_tab[nfc_proto->id]) 588c2ecf20Sopenharmony_ci rc = -EBUSY; 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci proto_tab[nfc_proto->id] = nfc_proto; 618c2ecf20Sopenharmony_ci write_unlock(&proto_tab_lock); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (rc) 648c2ecf20Sopenharmony_ci proto_unregister(nfc_proto->proto); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return rc; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_proto_register); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_civoid nfc_proto_unregister(const struct nfc_protocol *nfc_proto) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci write_lock(&proto_tab_lock); 738c2ecf20Sopenharmony_ci proto_tab[nfc_proto->id] = NULL; 748c2ecf20Sopenharmony_ci write_unlock(&proto_tab_lock); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci proto_unregister(nfc_proto->proto); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_proto_unregister); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciint __init af_nfc_init(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return sock_register(&nfc_sock_family_ops); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid af_nfc_exit(void) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci sock_unregister(PF_NFC); 888c2ecf20Sopenharmony_ci} 89