162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011 Instituto Nokia de Tecnologia 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> 762306a36Sopenharmony_ci * Lauro Ramos Venancio <lauro.venancio@openbossa.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/nfc.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "nfc.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic DEFINE_RWLOCK(proto_tab_lock); 1662306a36Sopenharmony_cistatic const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX]; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int nfc_sock_create(struct net *net, struct socket *sock, int proto, 1962306a36Sopenharmony_ci int kern) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci int rc = -EPROTONOSUPPORT; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (net != &init_net) 2462306a36Sopenharmony_ci return -EAFNOSUPPORT; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (proto < 0 || proto >= NFC_SOCKPROTO_MAX) 2762306a36Sopenharmony_ci return -EINVAL; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci read_lock(&proto_tab_lock); 3062306a36Sopenharmony_ci if (proto_tab[proto] && try_module_get(proto_tab[proto]->owner)) { 3162306a36Sopenharmony_ci rc = proto_tab[proto]->create(net, sock, proto_tab[proto], kern); 3262306a36Sopenharmony_ci module_put(proto_tab[proto]->owner); 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci read_unlock(&proto_tab_lock); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return rc; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const struct net_proto_family nfc_sock_family_ops = { 4062306a36Sopenharmony_ci .owner = THIS_MODULE, 4162306a36Sopenharmony_ci .family = PF_NFC, 4262306a36Sopenharmony_ci .create = nfc_sock_create, 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciint nfc_proto_register(const struct nfc_protocol *nfc_proto) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int rc; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (nfc_proto->id < 0 || nfc_proto->id >= NFC_SOCKPROTO_MAX) 5062306a36Sopenharmony_ci return -EINVAL; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci rc = proto_register(nfc_proto->proto, 0); 5362306a36Sopenharmony_ci if (rc) 5462306a36Sopenharmony_ci return rc; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci write_lock(&proto_tab_lock); 5762306a36Sopenharmony_ci if (proto_tab[nfc_proto->id]) 5862306a36Sopenharmony_ci rc = -EBUSY; 5962306a36Sopenharmony_ci else 6062306a36Sopenharmony_ci proto_tab[nfc_proto->id] = nfc_proto; 6162306a36Sopenharmony_ci write_unlock(&proto_tab_lock); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (rc) 6462306a36Sopenharmony_ci proto_unregister(nfc_proto->proto); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return rc; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_proto_register); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_civoid nfc_proto_unregister(const struct nfc_protocol *nfc_proto) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci write_lock(&proto_tab_lock); 7362306a36Sopenharmony_ci proto_tab[nfc_proto->id] = NULL; 7462306a36Sopenharmony_ci write_unlock(&proto_tab_lock); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci proto_unregister(nfc_proto->proto); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ciEXPORT_SYMBOL(nfc_proto_unregister); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciint __init af_nfc_init(void) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return sock_register(&nfc_sock_family_ops); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_civoid __exit af_nfc_exit(void) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci sock_unregister(PF_NFC); 8862306a36Sopenharmony_ci} 89