18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Link Layer Control manager 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <net/nfc/llc.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "llc.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic LIST_HEAD(llc_engines); 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciint nfc_llc_init(void) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci int r; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci r = nfc_llc_nop_register(); 198c2ecf20Sopenharmony_ci if (r) 208c2ecf20Sopenharmony_ci goto exit; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci r = nfc_llc_shdlc_register(); 238c2ecf20Sopenharmony_ci if (r) 248c2ecf20Sopenharmony_ci goto exit; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciexit: 298c2ecf20Sopenharmony_ci nfc_llc_exit(); 308c2ecf20Sopenharmony_ci return r; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_civoid nfc_llc_exit(void) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct nfc_llc_engine *llc_engine, *n; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) { 388c2ecf20Sopenharmony_ci list_del(&llc_engine->entry); 398c2ecf20Sopenharmony_ci kfree(llc_engine->name); 408c2ecf20Sopenharmony_ci kfree(llc_engine); 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciint nfc_llc_register(const char *name, struct nfc_llc_ops *ops) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct nfc_llc_engine *llc_engine; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL); 498c2ecf20Sopenharmony_ci if (llc_engine == NULL) 508c2ecf20Sopenharmony_ci return -ENOMEM; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci llc_engine->name = kstrdup(name, GFP_KERNEL); 538c2ecf20Sopenharmony_ci if (llc_engine->name == NULL) { 548c2ecf20Sopenharmony_ci kfree(llc_engine); 558c2ecf20Sopenharmony_ci return -ENOMEM; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci llc_engine->ops = ops; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&llc_engine->entry); 608c2ecf20Sopenharmony_ci list_add_tail(&llc_engine->entry, &llc_engines); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct nfc_llc_engine *llc_engine; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci list_for_each_entry(llc_engine, &llc_engines, entry) { 708c2ecf20Sopenharmony_ci if (strcmp(llc_engine->name, name) == 0) 718c2ecf20Sopenharmony_ci return llc_engine; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return NULL; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid nfc_llc_unregister(const char *name) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct nfc_llc_engine *llc_engine; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci llc_engine = nfc_llc_name_to_engine(name); 828c2ecf20Sopenharmony_ci if (llc_engine == NULL) 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci list_del(&llc_engine->entry); 868c2ecf20Sopenharmony_ci kfree(llc_engine->name); 878c2ecf20Sopenharmony_ci kfree(llc_engine); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev, 918c2ecf20Sopenharmony_ci xmit_to_drv_t xmit_to_drv, 928c2ecf20Sopenharmony_ci rcv_to_hci_t rcv_to_hci, int tx_headroom, 938c2ecf20Sopenharmony_ci int tx_tailroom, llc_failure_t llc_failure) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct nfc_llc_engine *llc_engine; 968c2ecf20Sopenharmony_ci struct nfc_llc *llc; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci llc_engine = nfc_llc_name_to_engine(name); 998c2ecf20Sopenharmony_ci if (llc_engine == NULL) 1008c2ecf20Sopenharmony_ci return NULL; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL); 1038c2ecf20Sopenharmony_ci if (llc == NULL) 1048c2ecf20Sopenharmony_ci return NULL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci, 1078c2ecf20Sopenharmony_ci tx_headroom, tx_tailroom, 1088c2ecf20Sopenharmony_ci &llc->rx_headroom, &llc->rx_tailroom, 1098c2ecf20Sopenharmony_ci llc_failure); 1108c2ecf20Sopenharmony_ci if (llc->data == NULL) { 1118c2ecf20Sopenharmony_ci kfree(llc); 1128c2ecf20Sopenharmony_ci return NULL; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci llc->ops = llc_engine->ops; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return llc; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid nfc_llc_free(struct nfc_llc *llc) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci llc->ops->deinit(llc); 1228c2ecf20Sopenharmony_ci kfree(llc); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciint nfc_llc_start(struct nfc_llc *llc) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci return llc->ops->start(llc); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_llc_start); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciint nfc_llc_stop(struct nfc_llc *llc) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return llc->ops->stop(llc); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_llc_stop); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_civoid nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci llc->ops->rcv_from_drv(llc, skb); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciint nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return llc->ops->xmit_from_hci(llc, skb); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid *nfc_llc_get_data(struct nfc_llc *llc) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci return llc->data; 1508c2ecf20Sopenharmony_ci} 151